From 206dfcbdd5b51d9d41a0a69d0b19989725829824 Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Mon, 10 Aug 2026 14:08:26 -0700 Subject: [PATCH 01/48] docs: proposal for the Solid 2.0 documentation rebuild Co-authored-by: Cursor --- PROPOSAL-solid-2.0-docs.md | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 PROPOSAL-solid-2.0-docs.md diff --git a/PROPOSAL-solid-2.0-docs.md b/PROPOSAL-solid-2.0-docs.md new file mode 100644 index 000000000..81ea824be --- /dev/null +++ b/PROPOSAL-solid-2.0-docs.md @@ -0,0 +1,116 @@ +# Proposal: Solid 2.0 documentation structure + +Solid 2.0 is a platform-wide change: `solid-js` 2.0, `@solidjs/web` 2.0, `@solidjs/router` 2.0, `@solidjs/meta` 1.0, and `vite-plugin-solid` 3.0 ship together and only work together. There is no SolidStart on this platform: SolidStart 2.0 is a Solid 1.x product and does not support Solid 2.0. Its role is taken by the `start` mode of the Vite plugin. This proposal restructures the docs site to match. + +## The problem with the current structure + +The site is organized as four products (Solid, Router, Start, Meta), each with its own version dropdown. That model worked when packages versioned independently. For 2.0 it breaks: + +- **The versions are correlated, and the labels lie about it.** A reader on Solid v2 docs who clicks into the Router section lands on docs for a package that cannot exist in their app. Today, Meta's newest docs sit under a "v1" dropdown entry while "latest" is the old package, and Router has no new entry at all. Worst of all, SolidStart's "v2" sits beside Solid's "v2" in the nav while not supporting Solid 2.0 — the labels invite exactly the wrong conclusion. +- **The product boundaries dissolved.** `useHead` lives in `@solidjs/web`. Response helpers moved from the router to `@solidjs/web`. Single-flight mutations span the router and the plugin. Start is a plugin option. Per-package silos force readers to know which package owns a feature before they can find it. +- **The stack is router-agnostic.** TanStack Router + Query is a supported first-class path (the `fullstack-tanstack` template exists to prove it). Docs that bake `@solidjs/router` into the core learning path contradict the architecture. + +## Proposed structure + +Split into two sites, the way Vite handles major versions: + +| Site | Contents | Status | +| --- | --- | --- | +| **v1.docs.solidjs.com** | The current site as it stands: core at `/`, Router 1, Meta 0.29, Start v1 + v2 (Start 2 runs on Solid 1, so it lives here) | Branched off and frozen in shape, maintained for fixes | +| **docs.solidjs.com** | One unified doc tree covering the Solid 2.0 platform, rebuilt from a clean starting point | The active effort | + +Since everything is touched by Solid 2.0, branching the whole site beats threading version switches through every page. Each site links to the other from a banner. This is a one-time split for this transition, not a policy for every major version. + +Package versions stop being a navigation concern entirely. Reference pages state "as of `@solidjs/router` 2.0" in frontmatter; the reader never picks versions per section. + +### Search + +Search is a forcing function for the split, not an afterthought. Today the site syncs one flat Orama Cloud index (`scripts/sync-orama.mjs`, documents of `content` / `path` / `section` / `title`) with no version facet — which is why searches surface Start 1 pages to Start 2 users, and why Solid 2 content would make results incoherent. Two sites mean two Orama projects: every result on docs.solidjs.com is a Solid 2.0 result, by construction. The v1 site keeps the existing index unchanged. + +### The 2.0 tree + +The sidebar keeps the existing Learn / Reference tab split. + +#### Learn + +| Section | Contents | +| --- | --- | +| **Overview** | What Solid 2.0 is, state of the beta, how the docs are organized | +| **Getting started** | Quick start (degit a template tier, run it, tour `App.tsx` / `Document.tsx`). Project shapes: `bare` / `basic` / `fullstack`, the deployment contract of each tier, the `ssr` flip | +| **Concepts** | The framework itself. No router, no server. Reactivity basics (signals, memos, effects). Async reactivity (`isPending`, `latest`, `flush`, `onSettled`, actions and `refresh`). Stores, projections, optimistic updates. Components and JSX control flow. Boundaries (`Loading`, `Errored`, `Reveal`). The rendering and SSR model | +| **Building apps** | The platform layer, router-neutral throughout. App structure (`App` / `Document` conventions, generated entries, `start` options). Styling and assets. Head and metadata (the Meta 1.0 components). Server functions. Sessions and auth. Typed environment variables and `server-only` / `client-only`. Middleware and API routes. Deployment (`handleRequest`, adapters, hosts) | +| **Routing** | The explicit choice point. An overview page documents the router seam: how a router mounts inside `App`, consumes `virtual:file-routes`, and participates in single-flight. Below it, two paths: **Solid Router** (the first-party default, full narrative docs written for 2.0) and **TanStack** (Router + Query integration guide, linking out for the router itself) | +| **Guides** | Task how-tos: testing (client and server postures), custom hosts (workers, Cloudflare), progressive enhancement and no-JS forms, and so on | +| **Migration** | One hub: from Solid 1.x (rename table, dropped APIs, the async model), from SolidStart (both the vinxi-era v1 and the released v2), from Router 0.x/1.x, from Meta 0.x | + +#### Reference + +Grouped by import specifier, generated from source where possible: + +- `solid-js` +- `@solidjs/web` +- `@solidjs/router` +- `@solidjs/meta` +- `vite-plugin-solid` (full `Options` / `StartOptions` / `ServerFunctionsOptions` surface) +- `filesystem-routing` + +### Route layout + +No version prefix — the new site is Solid 2.0 at the root: + +``` +src/routes/ + (0)index.mdx + (1)getting-started/ + (2)concepts/ + (3)building-apps/ + (4)routing/ + (0)overview.mdx + (1)solid-router/ + (2)tanstack/ + (5)guides/ + (6)migration/ + reference/ + solid-js/ + solid-web/ + solid-router/ + solid-meta/ + vite-plugin-solid/ + filesystem-routing/ +``` + +## Reasoning for the contentious calls + +**Routing is its own section, not a Building Apps page.** It is the one place the reader makes a real choice, and both choices need room. `@solidjs/router` earns a full subtree (nested routes, preload, typed paths, actions). TanStack gets a real integration guide rather than a footnote. Every page in Building Apps is written to read correctly regardless of that choice. + +**Meta and Start dissolve as products.** Meta 1.0 is eight components: one Building Apps page plus reference. Start's guides become Building Apps pages; its name survives in Getting Started ("start mode") and the migration hub. + +**Reference splits `solid-js` from `@solidjs/web`.** The current v2 reference mixes them. Splitting by specifier matches what users import and where things now live (`useHead`, `clientOnly`, `redirect` / `respond` are all `@solidjs/web`). + +**Getting started leads with the template tiers.** They are real, maintained, and each is a deployment contract. That beats an abstract install page, and the tier READMEs already model the tone the docs want. + +## What moves, what gets written + +| Content | Motion | +| --- | --- | +| 69 generated v2 reference pages | Re-sort into `reference/solid-js` and `reference/solid-web`; regenerate via `scripts/extract-solid-ref.mjs` | +| `solid-meta/v1/*` | Relocates nearly as-is into Building Apps + `reference/solid-meta` | +| `solid-start/v2` guides | Port into Building Apps, rewriting where the Start 2 API differs from start mode | +| Router 2.0 narrative + reference | **Net-new writing** | +| Concepts section | **Net-new writing** (adapted from v1 concepts against the 2.0 API) | +| Migration guides (beyond core) | **Net-new writing** (Router README on `next` has a migration section to seed from) | + +The true size of the writing effort is Concepts, Routing, and Migration. Everything else is reorganization. + +## Open questions + +1. **Staging.** Where does the 2.0 site live while under construction — a preview deployment, or does the split happen up front with the new site carrying a beta banner? The v1 branch-off itself is cheap and can happen at any point. +2. **Redirects.** Existing deep links into today's site: which URLs redirect to the v1 subdomain versus mapping to their 2.0 equivalents? The middleware redirect layer already exists to implement whatever mapping is chosen. + +## Suggested sequencing + +1. **Foundations.** Writing-guide addendum for AI-assisted drafting (banned filler and marketing language, claims traceable to source) plus a CI tone lint. Reconcile the existing generated reference (a handful of missing pages, one stale page). +2. **Skeleton.** Branch the current site off for the v1 subdomain, then land the folder structure and nav config above from a clean starting point; move the content that relocates cleanly. +3. **Concepts.** The biggest user-facing hole: 2.0 beta users currently have API lookup but no way to learn the model. +4. **Routing + Migration.** Router 2.0 narrative docs, the TanStack integration guide, and the migration hub. +5. **Building Apps.** Port and rewrite the Start guides against start mode. From 51fd6e8bd8ac0c9c9914a0ab966568c6a456896b Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Mon, 10 Aug 2026 14:20:21 -0700 Subject: [PATCH 02/48] docs: restructure to the unified Solid 2.0 site layout Implements the rebuild proposal: single-version site with the new IA (getting-started, concepts, building-apps, routing, guides, migration, reference by package). Moves the generated v2 reference under reference/solid-js and reference/solid-web, relocates the Meta 1.0 docs, adds planned-page stubs, and removes the per-project version routing, project tabs, and legacy redirect middleware. Co-authored-by: Cursor --- osmium/src/ui/layout/main-header.tsx | 6 +- osmium/src/utils.ts | 7 +- src/middleware/index.ts | 5 +- src/middleware/legacy-routes-redirect.ts | 217 ----- .../(0)concepts/(0)components/(0)basics.mdx | 312 ------- .../(0)components/(1)class-style.mdx | 125 --- .../(0)concepts/(0)components/(2)props.mdx | 134 --- .../(0)components/(3)event-handlers.mdx | 233 ----- .../(0)concepts/(0)intro-to-reactivity.mdx | 264 ------ .../(0)conditional-rendering.mdx | 102 --- .../(1)control-flow/(1)list-rendering.mdx | 169 ---- .../(1)control-flow/(2)dynamic.mdx | 115 --- .../(1)control-flow/(3)error-boundary.mdx | 56 -- .../(0)concepts/(1)control-flow/(4)portal.mdx | 77 -- .../(0)concepts/(1)understanding-jsx.mdx | 145 --- .../(2)derived-values/(0)derived-signals.mdx | 44 - .../(2)derived-values/(1)memos.mdx | 162 ---- src/routes/(0)concepts/(2)signals.mdx | 105 --- src/routes/(0)concepts/(3)effects.mdx | 213 ----- src/routes/(0)concepts/(4)context.mdx | 278 ------ src/routes/(0)concepts/(5)stores.mdx | 529 ----------- src/routes/(0)concepts/(6)refs.mdx | 195 ---- src/routes/(0)index.mdx | 82 +- .../(0)fine-grained-reactivity.mdx | 305 ------- .../(1)getting-started/(0)quick-start.mdx | 38 + .../(1)getting-started/(1)project-shapes.mdx | 54 ++ src/routes/(1)quick-start.mdx | 93 -- src/routes/(2)concepts/(0)reactivity.mdx | 11 + .../(2)concepts/(1)async-reactivity.mdx | 11 + src/routes/(2)concepts/(2)stores.mdx | 11 + .../(2)concepts/(3)components-and-jsx.mdx | 11 + src/routes/(2)concepts/(4)boundaries.mdx | 11 + .../(2)concepts/(5)rendering-and-ssr.mdx | 11 + .../(0)styling-components/css-modules.mdx | 99 -- .../(2)guides/(0)styling-components/less.mdx | 77 -- .../(0)styling-components/macaron.mdx | 120 --- .../(2)guides/(0)styling-components/sass.mdx | 80 -- .../(0)styling-components/tailwind-v3.mdx | 104 --- .../(0)styling-components/tailwind.mdx | 95 -- .../(2)guides/(0)styling-components/uno.mdx | 98 -- .../(2)guides/(0)styling-your-components.mdx | 77 -- .../aws-via-flightcontrol.mdx | 111 --- .../(1)deployment-options/aws-via-sst.mdx | 63 -- .../(1)deployment-options/cloudflare.mdx | 97 -- .../(1)deployment-options/firebase.mdx | 68 -- .../(1)deployment-options/netlify.mdx | 74 -- .../(1)deployment-options/railway.mdx | 108 --- .../(1)deployment-options/stormkit.mdx | 36 - .../(1)deployment-options/vercel.mdx | 78 -- .../(1)deployment-options/zerops.mdx | 181 ---- src/routes/(2)guides/(1)state-management.mdx | 366 -------- .../(2)guides/(2)routing-and-navigation.mdx | 530 ----------- .../(2)guides/(3)complex-state-management.mdx | 378 -------- src/routes/(2)guides/(4)fetching-data.mdx | 210 ----- src/routes/(2)guides/(5)testing.mdx | 552 ------------ .../(2)guides/(6)deploying-your-app.mdx | 74 -- .../(3)building-apps/(0)app-structure.mdx | 11 + .../(1)styling-and-assets.mdx | 11 + .../(2)head-and-metadata.mdx} | 15 +- .../(3)building-apps/(3)server-functions.mdx | 11 + .../(3)building-apps/(4)sessions-and-auth.mdx | 11 + .../(3)building-apps/(5)environment.mdx | 11 + .../(6)middleware-and-api-routes.mdx | 11 + src/routes/(3)building-apps/(7)deployment.mdx | 11 + .../(0)environment-variables.mdx | 106 --- src/routes/(3)configuration/(1)typescript.mdx | 845 ------------------ src/routes/(4)routing/(0)overview.mdx | 11 + .../(4)routing/(1)solid-router/(0)index.mdx | 11 + .../(4)routing/(2)tanstack/(0)index.mdx | 11 + src/routes/(5)guides/(0)testing.mdx | 11 + src/routes/(6)migration/(0)from-solid-1.mdx | 11 + .../(6)migration/(1)from-solid-start.mdx | 11 + .../(6)migration/(2)from-solid-router.mdx | 11 + .../(3)from-solid-meta.mdx} | 8 +- .../(1)reactivity/create-effect.mdx | 0 .../(1)reactivity/create-memo.mdx | 0 .../(1)reactivity/create-optimistic.mdx | 0 .../(1)reactivity/create-signal.mdx | 0 .../(1)solid-js}/(1)reactivity/flush.mdx | 0 .../(1)solid-js}/(1)reactivity/is-pending.mdx | 0 .../(1)solid-js}/(1)reactivity/latest.mdx | 0 .../(1)solid-js}/(1)reactivity/untrack.mdx | 0 .../(2)stores/create-optimistic-store.mdx | 0 .../(2)stores/create-projection.mdx | 0 .../(1)solid-js}/(2)stores/create-store.mdx | 0 .../(1)solid-js}/(2)stores/merge.mdx | 0 .../(1)solid-js}/(2)stores/omit.mdx | 0 .../(1)solid-js}/(2)stores/reconcile.mdx | 0 .../(3)lifecycle-actions/action.mdx | 0 .../(3)lifecycle-actions/on-settled.mdx | 0 .../(3)lifecycle-actions/refresh.mdx | 0 .../(4)components-context/children.mdx | 0 .../(4)components-context/create-context.mdx | 0 .../create-unique-id.mdx | 0 .../(4)components-context/dynamic.mdx | 0 .../(4)components-context/lazy.mdx | 0 .../(4)components-context/use-context.mdx | 0 .../(5)components-jsx/dynamic.mdx | 0 .../(5)components-jsx/errored.mdx | 0 .../(1)solid-js}/(5)components-jsx/for.mdx | 0 .../(5)components-jsx/loading.mdx | 0 .../(1)solid-js}/(5)components-jsx/portal.mdx | 0 .../(1)solid-js}/(5)components-jsx/repeat.mdx | 0 .../(1)solid-js}/(5)components-jsx/reveal.mdx | 0 .../(1)solid-js}/(5)components-jsx/show.mdx | 0 .../(5)components-jsx/switch-and-match.mdx | 0 .../(1)owner-introspection/create-root.mdx | 0 .../(1)owner-introspection/get-observer.mdx | 0 .../(1)owner-introspection/get-owner.mdx | 0 .../(1)owner-introspection/is-disposed.mdx | 0 .../(1)owner-introspection/run-with-owner.mdx | 0 .../create-reaction.mdx | 0 .../create-render-effect.mdx | 0 .../create-tracked-effect.mdx | 0 .../(2)specialized-reactivity/on-cleanup.mdx | 2 +- .../(6)advanced}/(3)store-advanced/deep.mdx | 0 .../(3)store-advanced/is-wrappable.mdx | 0 .../(3)store-advanced/snapshot.mdx | 0 .../(3)store-advanced/store-path.mdx | 0 .../create-error-boundary.mdx | 0 .../create-loading-boundary.mdx | 0 .../create-reveal-order.mdx | 0 .../(4)jsx-component-primitives/map-array.mdx | 0 .../(4)jsx-component-primitives/repeat.mdx | 0 .../(5)manual-hydration/hydration.mdx | 0 .../(5)manual-hydration/no-hydration.mdx | 0 .../enable-external-source.mdx | 0 .../(6)advanced}/(6)interop-async/flatten.mdx | 0 .../(6)interop-async/not-ready-error.mdx | 0 .../(6)advanced}/(6)interop-async/resolve.mdx | 0 .../(7)diagnostics-dev-hooks/dev.mdx | 0 .../(1)solid-js/(7)types}/component-types.mdx | 0 .../(1)solid-js/(7)types}/context-types.mdx | 0 .../(1)solid-js/(7)types}/owner.mdx | 0 .../(1)solid-js/(7)types}/reactive-types.mdx | 0 .../(1)solid-js/(7)types}/store-types.mdx | 0 .../(1)rendering-ssr}/hydrate.mdx | 0 .../(2)solid-web/(1)rendering-ssr}/is-dev.mdx | 0 .../(1)rendering-ssr}/is-server.mdx | 0 .../(1)rendering-ssr}/render-to-stream.mdx | 0 .../render-to-string-async.mdx | 0 .../(1)rendering-ssr}/render-to-string.mdx | 0 .../(2)solid-web/(1)rendering-ssr}/render.mdx | 0 .../reference/(3)solid-router/(0)index.mdx | 11 + .../meta => reference/(4)solid-meta}/base.mdx | 4 +- .../meta => reference/(4)solid-meta}/head.mdx | 4 +- .../meta => reference/(4)solid-meta}/link.mdx | 4 +- .../meta => reference/(4)solid-meta}/meta.mdx | 6 +- .../(4)solid-meta}/script.mdx | 4 +- .../(4)solid-meta}/style.mdx | 4 +- .../(4)solid-meta}/stylesheet.mdx | 6 +- .../(4)solid-meta}/title.mdx | 4 +- .../(5)vite-plugin-solid/(0)index.mdx | 11 + .../(6)filesystem-routing/(0)index.mdx | 11 + .../basic-reactivity/create-effect.mdx | 175 ---- .../basic-reactivity/create-memo.mdx | 218 ----- .../basic-reactivity/create-resource.mdx | 268 ------ .../basic-reactivity/create-signal.mdx | 123 --- .../reference/component-apis/children.mdx | 106 --- .../component-apis/create-context.mdx | 113 --- .../component-apis/create-unique-id.mdx | 78 -- src/routes/reference/component-apis/lazy.mdx | 110 --- .../reference/component-apis/use-context.mdx | 100 --- .../reference/components/create-dynamic.mdx | 91 -- src/routes/reference/components/dynamic.mdx | 96 -- .../reference/components/error-boundary.mdx | 86 -- src/routes/reference/components/for.mdx | 101 --- .../reference/components/index-component.mdx | 101 --- .../reference/components/no-hydration.mdx | 69 -- src/routes/reference/components/portal.mdx | 119 --- src/routes/reference/components/show.mdx | 120 --- .../reference/components/suspense-list.mdx | 117 --- src/routes/reference/components/suspense.mdx | 121 --- .../reference/components/switch-and-match.mdx | 132 --- src/routes/reference/jsx-attributes/attr.mdx | 51 -- src/routes/reference/jsx-attributes/bool.mdx | 60 -- .../reference/jsx-attributes/classlist.mdx | 66 -- .../reference/jsx-attributes/innerhtml.mdx | 51 -- src/routes/reference/jsx-attributes/on.mdx | 88 -- src/routes/reference/jsx-attributes/on_.mdx | 61 -- src/routes/reference/jsx-attributes/once.mdx | 43 - src/routes/reference/jsx-attributes/prop.mdx | 52 -- src/routes/reference/jsx-attributes/ref.mdx | 71 -- src/routes/reference/jsx-attributes/style.mdx | 67 -- .../reference/jsx-attributes/textcontent.mdx | 45 - src/routes/reference/jsx-attributes/use.mdx | 77 -- src/routes/reference/lifecycle/on-cleanup.mdx | 104 --- src/routes/reference/lifecycle/on-mount.mdx | 100 --- .../reference/reactive-utilities/batch.mdx | 105 --- .../reactive-utilities/catch-error.mdx | 90 -- .../reactive-utilities/create-root.mdx | 130 --- .../reference/reactive-utilities/from.mdx | 118 --- .../reactive-utilities/get-owner.mdx | 81 -- .../reactive-utilities/index-array.mdx | 95 -- .../reactive-utilities/map-array.mdx | 97 -- .../reactive-utilities/merge-props.mdx | 75 -- .../reactive-utilities/observable.mdx | 71 -- .../reference/reactive-utilities/on-util.mdx | 85 -- .../reactive-utilities/run-with-owner.mdx | 91 -- .../reactive-utilities/split-props.mdx | 103 --- .../reactive-utilities/start-transition.mdx | 94 -- .../reference/reactive-utilities/untrack.mdx | 121 --- .../reactive-utilities/use-transition.mdx | 98 -- src/routes/reference/rendering/dev.mdx | 67 -- src/routes/reference/rendering/hydrate.mdx | 93 -- .../reference/rendering/hydration-script.mdx | 110 --- src/routes/reference/rendering/is-dev.mdx | 50 -- src/routes/reference/rendering/is-server.mdx | 50 -- .../reference/rendering/render-to-stream.mdx | 113 --- .../rendering/render-to-string-async.mdx | 93 -- .../reference/rendering/render-to-string.mdx | 85 -- src/routes/reference/rendering/render.mdx | 71 -- .../secondary-primitives/create-computed.mdx | 127 --- .../secondary-primitives/create-deferred.mdx | 111 --- .../secondary-primitives/create-reaction.mdx | 84 -- .../create-render-effect.mdx | 134 --- .../secondary-primitives/create-selector.mdx | 105 --- .../server-utilities/get-request-event.mdx | 57 -- .../store-utilities/create-mutable.mdx | 101 --- .../store-utilities/create-store.mdx | 105 --- .../store-utilities/modify-mutable.mdx | 80 -- .../reference/store-utilities/produce.mdx | 74 -- .../reference/store-utilities/reconcile.mdx | 84 -- .../reference/store-utilities/unwrap.mdx | 67 -- .../(0)installation-and-setup.mdx | 70 -- .../(0)getting-started/(1)client-setup.mdx | 35 - .../(0)getting-started/(2)server-setup.mdx | 47 - src/routes/solid-meta/(0)index.mdx | 29 - src/routes/solid-meta/reference/meta/base.mdx | 59 -- src/routes/solid-meta/reference/meta/link.mdx | 59 -- src/routes/solid-meta/reference/meta/meta.mdx | 62 -- .../reference/meta/metaprovider.mdx | 71 -- .../solid-meta/reference/meta/style.mdx | 70 -- .../solid-meta/reference/meta/title.mdx | 66 -- .../solid-meta/reference/meta/use-head.mdx | 192 ---- src/routes/solid-meta/v1/(0)index.mdx | 34 - .../(0)installation-and-setup.mdx | 54 -- .../(0)getting-started/(1)component.mdx | 63 -- .../(0)getting-started/(2)config.mdx | 94 -- .../(0)getting-started/(3)linking-routes.mdx | 90 -- src/routes/solid-router/(0)index.mdx | 30 - .../(1)concepts/(0)navigation.mdx | 123 --- .../(1)concepts/(1)path-parameters.mdx | 132 --- .../(1)concepts/(2)search-parameters.mdx | 82 -- .../solid-router/(1)concepts/(3)catch-all.mdx | 40 - .../(1)concepts/(4)dynamic-routes.mdx | 135 --- .../solid-router/(1)concepts/(5)nesting.mdx | 96 -- .../solid-router/(1)concepts/(6)layouts.mdx | 87 -- .../(1)concepts/(7)alternative-routers.mdx | 83 -- .../solid-router/(1)concepts/(8)actions.mdx | 461 ---------- .../(2)rendering-modes/(0)spa.mdx | 40 - .../(2)rendering-modes/(1)ssr.mdx | 31 - .../(3)data-fetching/(0)queries.mdx | 81 -- .../(3)data-fetching/(1)streaming.mdx | 90 -- .../(3)data-fetching/(2)revalidation.mdx | 60 -- .../how-to/(0)preload-data.mdx | 54 -- .../(1)handle-error-and-loading-states.mdx | 29 - .../(4)advanced-concepts/(0)preloading.mdx | 44 - .../(4)advanced-concepts/(1)lazy-loading.mdx | 42 - .../solid-router/(5)guides/(0)migration.mdx | 85 -- .../solid-router/reference/components/a.mdx | 140 --- .../reference/components/hash-router.mdx | 145 --- .../reference/components/memory-router.mdx | 173 ---- .../reference/components/navigate.mdx | 95 -- .../reference/components/route.mdx | 121 --- .../reference/components/router.mdx | 163 ---- .../reference/data-apis/action.mdx | 146 --- .../reference/data-apis/cache.mdx | 59 -- .../data-apis/create-async-store.mdx | 167 ---- .../reference/data-apis/create-async.mdx | 198 ---- .../reference/data-apis/query.mdx | 184 ---- .../reference/data-apis/revalidate.mdx | 126 --- .../reference/data-apis/use-action.mdx | 69 -- .../reference/data-apis/use-submission.mdx | 128 --- .../reference/data-apis/use-submissions.mdx | 191 ---- .../reference/preload-functions/preload.mdx | 108 --- .../reference/primitives/use-before-leave.mdx | 92 -- .../primitives/use-current-matches.mdx | 68 -- .../reference/primitives/use-is-routing.mdx | 61 -- .../reference/primitives/use-location.mdx | 118 --- .../reference/primitives/use-match.mdx | 153 ---- .../reference/primitives/use-navigate.mdx | 154 ---- .../reference/primitives/use-params.mdx | 69 -- .../primitives/use-preload-route.mdx | 87 -- .../primitives/use-resolved-path.mdx | 65 -- .../primitives/use-search-params.mdx | 92 -- .../reference/response-helpers/json.mdx | 147 --- .../reference/response-helpers/redirect.mdx | 109 --- .../reference/response-helpers/reload.mdx | 89 -- .../(0)routing.mdx | 301 ------- .../(1)api-routes.mdx | 241 ----- .../(2)css-and-styling.mdx | 112 --- .../(3)data-fetching.mdx | 58 -- .../(4)data-mutation.mdx | 105 --- .../(5)head-and-metadata.mdx | 136 --- .../(6)route-prerendering.mdx | 53 -- .../(7)static-assets.mdx | 93 -- src/routes/solid-start/v1/(0)index.mdx | 60 -- .../v1/(1)advanced/(0)middleware.mdx | 292 ------ .../solid-start/v1/(1)advanced/(1)session.mdx | 144 --- .../v1/(1)advanced/(2)request-events.mdx | 45 - .../v1/(1)advanced/(3)return-responses.mdx | 62 -- .../v1/(1)advanced/(4)serialization.mdx | 78 -- .../solid-start/v1/(1)advanced/(5)auth.mdx | 61 -- .../v1/(1)advanced/(6)websocket.mdx | 63 -- .../solid-start/v1/(1)getting-started.mdx | 117 --- .../solid-start/v1/(2)guides/(0)security.mdx | 217 ----- .../v1/(2)guides/(1)data-fetching.mdx | 396 -------- .../v1/(2)guides/(2)data-mutation.mdx | 557 ------------ .../v1/(2)guides/(3)service-workers.mdx | 34 - .../v1/(2)guides/(4)background-tasks.mdx | 115 --- .../v1/reference/client/client-only.mdx | 82 -- .../solid-start/v1/reference/client/mount.mdx | 73 -- .../v1/reference/client/start-client.mdx | 55 -- .../v1/reference/config/define-config.mdx | 174 ---- .../reference/entrypoints/(0)app-config.mdx | 52 -- .../v1/reference/entrypoints/app.mdx | 61 -- .../v1/reference/entrypoints/entry-client.mdx | 55 -- .../v1/reference/entrypoints/entry-server.mdx | 68 -- .../v1/reference/routing/file-routes.mdx | 60 -- .../v1/reference/server/create-handler.mdx | 105 --- .../v1/reference/server/create-middleware.mdx | 81 -- .../server/get-server-function-meta.mdx | 54 -- .../solid-start/v1/reference/server/get.mdx | 57 -- .../v1/reference/server/http-header.mdx | 74 -- .../v1/reference/server/http-status-code.mdx | 66 -- .../v1/reference/server/start-server.mdx | 77 -- .../v1/reference/server/use-server.mdx | 64 -- .../(0)routing.mdx | 84 -- .../(1)api-routes.mdx | 90 -- .../(2)css-and-styling.mdx | 201 ----- .../(3)data-fetching.mdx | 89 -- .../(4)data-mutation.mdx | 112 --- .../(5)head-and-metadata.mdx | 99 -- .../(6)route-prerendering.mdx | 57 -- .../(7)static-assets.mdx | 93 -- src/routes/solid-start/v2/(0)index.mdx | 27 - .../v2/(1)advanced/(0)middleware.mdx | 155 ---- .../solid-start/v2/(1)advanced/(1)session.mdx | 87 -- .../v2/(1)advanced/(2)request-events.mdx | 56 -- .../v2/(1)advanced/(3)return-responses.mdx | 62 -- .../v2/(1)advanced/(4)serialization.mdx | 144 --- .../solid-start/v2/(1)advanced/(5)auth.mdx | 61 -- .../v2/(1)advanced/(6)websocket.mdx | 72 -- .../solid-start/v2/(1)getting-started.mdx | 111 --- .../solid-start/v2/(2)guides/(0)security.mdx | 220 ----- .../v2/(2)guides/(1)data-fetching.mdx | 396 -------- .../v2/(2)guides/(2)data-mutation.mdx | 557 ------------ .../v2/(2)guides/(3)service-workers.mdx | 34 - .../v2/(2)guides/(4)background-tasks.mdx | 89 -- .../v2/(2)guides/(5)deployment-plugins.mdx | 87 -- .../solid-start/v2/(2)migrating-from-v1.mdx | 174 ---- .../v2/reference/client/client-only.mdx | 75 -- .../solid-start/v2/reference/client/mount.mdx | 71 -- .../v2/reference/client/start-client.mdx | 55 -- .../v2/reference/config/solid-start.mdx | 209 ----- .../reference/entrypoints/(0)vite-config.mdx | 59 -- .../v2/reference/entrypoints/app.mdx | 60 -- .../v2/reference/entrypoints/entry-client.mdx | 54 -- .../v2/reference/entrypoints/entry-server.mdx | 67 -- .../v2/reference/routing/file-routes.mdx | 63 -- .../v2/reference/server/create-handler.mdx | 103 --- .../v2/reference/server/create-middleware.mdx | 68 -- .../server/get-server-function-meta.mdx | 58 -- .../solid-start/v2/reference/server/get.mdx | 61 -- .../v2/reference/server/http-header.mdx | 73 -- .../v2/reference/server/http-status-code.mdx | 65 -- .../v2/reference/server/start-server.mdx | 77 -- .../v2/reference/server/use-server.mdx | 76 -- src/routes/v2/(0)index.mdx | 30 - src/routes/v2/(1)getting-started.mdx | 28 - vite.config.ts | 166 +--- 372 files changed, 430 insertions(+), 30981 deletions(-) delete mode 100644 src/middleware/legacy-routes-redirect.ts delete mode 100644 src/routes/(0)concepts/(0)components/(0)basics.mdx delete mode 100644 src/routes/(0)concepts/(0)components/(1)class-style.mdx delete mode 100644 src/routes/(0)concepts/(0)components/(2)props.mdx delete mode 100644 src/routes/(0)concepts/(0)components/(3)event-handlers.mdx delete mode 100644 src/routes/(0)concepts/(0)intro-to-reactivity.mdx delete mode 100644 src/routes/(0)concepts/(1)control-flow/(0)conditional-rendering.mdx delete mode 100644 src/routes/(0)concepts/(1)control-flow/(1)list-rendering.mdx delete mode 100644 src/routes/(0)concepts/(1)control-flow/(2)dynamic.mdx delete mode 100644 src/routes/(0)concepts/(1)control-flow/(3)error-boundary.mdx delete mode 100644 src/routes/(0)concepts/(1)control-flow/(4)portal.mdx delete mode 100644 src/routes/(0)concepts/(1)understanding-jsx.mdx delete mode 100644 src/routes/(0)concepts/(2)derived-values/(0)derived-signals.mdx delete mode 100644 src/routes/(0)concepts/(2)derived-values/(1)memos.mdx delete mode 100644 src/routes/(0)concepts/(2)signals.mdx delete mode 100644 src/routes/(0)concepts/(3)effects.mdx delete mode 100644 src/routes/(0)concepts/(4)context.mdx delete mode 100644 src/routes/(0)concepts/(5)stores.mdx delete mode 100644 src/routes/(0)concepts/(6)refs.mdx delete mode 100644 src/routes/(1)advanced-concepts/(0)fine-grained-reactivity.mdx create mode 100644 src/routes/(1)getting-started/(0)quick-start.mdx create mode 100644 src/routes/(1)getting-started/(1)project-shapes.mdx delete mode 100644 src/routes/(1)quick-start.mdx create mode 100644 src/routes/(2)concepts/(0)reactivity.mdx create mode 100644 src/routes/(2)concepts/(1)async-reactivity.mdx create mode 100644 src/routes/(2)concepts/(2)stores.mdx create mode 100644 src/routes/(2)concepts/(3)components-and-jsx.mdx create mode 100644 src/routes/(2)concepts/(4)boundaries.mdx create mode 100644 src/routes/(2)concepts/(5)rendering-and-ssr.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/css-modules.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/less.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/macaron.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/sass.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/tailwind-v3.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/tailwind.mdx delete mode 100644 src/routes/(2)guides/(0)styling-components/uno.mdx delete mode 100644 src/routes/(2)guides/(0)styling-your-components.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/aws-via-flightcontrol.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/aws-via-sst.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/cloudflare.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/firebase.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/netlify.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/railway.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/stormkit.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/vercel.mdx delete mode 100644 src/routes/(2)guides/(1)deployment-options/zerops.mdx delete mode 100644 src/routes/(2)guides/(1)state-management.mdx delete mode 100644 src/routes/(2)guides/(2)routing-and-navigation.mdx delete mode 100644 src/routes/(2)guides/(3)complex-state-management.mdx delete mode 100644 src/routes/(2)guides/(4)fetching-data.mdx delete mode 100644 src/routes/(2)guides/(5)testing.mdx delete mode 100644 src/routes/(2)guides/(6)deploying-your-app.mdx create mode 100644 src/routes/(3)building-apps/(0)app-structure.mdx create mode 100644 src/routes/(3)building-apps/(1)styling-and-assets.mdx rename src/routes/{solid-meta/v1/(1)getting-started.mdx => (3)building-apps/(2)head-and-metadata.mdx} (89%) create mode 100644 src/routes/(3)building-apps/(3)server-functions.mdx create mode 100644 src/routes/(3)building-apps/(4)sessions-and-auth.mdx create mode 100644 src/routes/(3)building-apps/(5)environment.mdx create mode 100644 src/routes/(3)building-apps/(6)middleware-and-api-routes.mdx create mode 100644 src/routes/(3)building-apps/(7)deployment.mdx delete mode 100644 src/routes/(3)configuration/(0)environment-variables.mdx delete mode 100644 src/routes/(3)configuration/(1)typescript.mdx create mode 100644 src/routes/(4)routing/(0)overview.mdx create mode 100644 src/routes/(4)routing/(1)solid-router/(0)index.mdx create mode 100644 src/routes/(4)routing/(2)tanstack/(0)index.mdx create mode 100644 src/routes/(5)guides/(0)testing.mdx create mode 100644 src/routes/(6)migration/(0)from-solid-1.mdx create mode 100644 src/routes/(6)migration/(1)from-solid-start.mdx create mode 100644 src/routes/(6)migration/(2)from-solid-router.mdx rename src/routes/{solid-meta/v1/(2)migrating-from-v0.mdx => (6)migration/(3)from-solid-meta.mdx} (89%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/create-effect.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/create-memo.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/create-optimistic.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/create-signal.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/flush.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/is-pending.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/latest.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(1)reactivity/untrack.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(2)stores/create-optimistic-store.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(2)stores/create-projection.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(2)stores/create-store.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(2)stores/merge.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(2)stores/omit.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(2)stores/reconcile.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(3)lifecycle-actions/action.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(3)lifecycle-actions/on-settled.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(3)lifecycle-actions/refresh.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(4)components-context/children.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(4)components-context/create-context.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(4)components-context/create-unique-id.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(4)components-context/dynamic.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(4)components-context/lazy.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(4)components-context/use-context.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/dynamic.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/errored.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/for.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/loading.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/portal.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/repeat.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/reveal.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/show.mdx (100%) rename src/routes/{v2/reference => reference/(1)solid-js}/(5)components-jsx/switch-and-match.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(1)owner-introspection/create-root.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(1)owner-introspection/get-observer.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(1)owner-introspection/get-owner.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(1)owner-introspection/is-disposed.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(1)owner-introspection/run-with-owner.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(2)specialized-reactivity/create-reaction.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(2)specialized-reactivity/create-render-effect.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(2)specialized-reactivity/create-tracked-effect.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(2)specialized-reactivity/on-cleanup.mdx (95%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(3)store-advanced/deep.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(3)store-advanced/is-wrappable.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(3)store-advanced/snapshot.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(3)store-advanced/store-path.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(4)jsx-component-primitives/create-error-boundary.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(4)jsx-component-primitives/create-loading-boundary.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(4)jsx-component-primitives/create-reveal-order.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(4)jsx-component-primitives/map-array.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(4)jsx-component-primitives/repeat.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(5)manual-hydration/hydration.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(5)manual-hydration/no-hydration.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(6)interop-async/enable-external-source.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(6)interop-async/flatten.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(6)interop-async/not-ready-error.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(6)interop-async/resolve.mdx (100%) rename src/routes/{v2/reference/(7)advanced => reference/(1)solid-js/(6)advanced}/(7)diagnostics-dev-hooks/dev.mdx (100%) rename src/routes/{v2/reference/(8)types => reference/(1)solid-js/(7)types}/component-types.mdx (100%) rename src/routes/{v2/reference/(8)types => reference/(1)solid-js/(7)types}/context-types.mdx (100%) rename src/routes/{v2/reference/(8)types => reference/(1)solid-js/(7)types}/owner.mdx (100%) rename src/routes/{v2/reference/(8)types => reference/(1)solid-js/(7)types}/reactive-types.mdx (100%) rename src/routes/{v2/reference/(8)types => reference/(1)solid-js/(7)types}/store-types.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/hydrate.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/is-dev.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/is-server.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/render-to-stream.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/render-to-string-async.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/render-to-string.mdx (100%) rename src/routes/{v2/reference/(6)rendering-ssr => reference/(2)solid-web/(1)rendering-ssr}/render.mdx (100%) create mode 100644 src/routes/reference/(3)solid-router/(0)index.mdx rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/base.mdx (93%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/head.mdx (95%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/link.mdx (95%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/meta.mdx (91%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/script.mdx (95%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/style.mdx (93%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/stylesheet.mdx (86%) rename src/routes/{solid-meta/v1/reference/meta => reference/(4)solid-meta}/title.mdx (93%) create mode 100644 src/routes/reference/(5)vite-plugin-solid/(0)index.mdx create mode 100644 src/routes/reference/(6)filesystem-routing/(0)index.mdx delete mode 100644 src/routes/reference/basic-reactivity/create-effect.mdx delete mode 100644 src/routes/reference/basic-reactivity/create-memo.mdx delete mode 100644 src/routes/reference/basic-reactivity/create-resource.mdx delete mode 100644 src/routes/reference/basic-reactivity/create-signal.mdx delete mode 100644 src/routes/reference/component-apis/children.mdx delete mode 100644 src/routes/reference/component-apis/create-context.mdx delete mode 100644 src/routes/reference/component-apis/create-unique-id.mdx delete mode 100644 src/routes/reference/component-apis/lazy.mdx delete mode 100644 src/routes/reference/component-apis/use-context.mdx delete mode 100644 src/routes/reference/components/create-dynamic.mdx delete mode 100644 src/routes/reference/components/dynamic.mdx delete mode 100644 src/routes/reference/components/error-boundary.mdx delete mode 100644 src/routes/reference/components/for.mdx delete mode 100644 src/routes/reference/components/index-component.mdx delete mode 100644 src/routes/reference/components/no-hydration.mdx delete mode 100644 src/routes/reference/components/portal.mdx delete mode 100644 src/routes/reference/components/show.mdx delete mode 100644 src/routes/reference/components/suspense-list.mdx delete mode 100644 src/routes/reference/components/suspense.mdx delete mode 100644 src/routes/reference/components/switch-and-match.mdx delete mode 100644 src/routes/reference/jsx-attributes/attr.mdx delete mode 100644 src/routes/reference/jsx-attributes/bool.mdx delete mode 100644 src/routes/reference/jsx-attributes/classlist.mdx delete mode 100644 src/routes/reference/jsx-attributes/innerhtml.mdx delete mode 100644 src/routes/reference/jsx-attributes/on.mdx delete mode 100644 src/routes/reference/jsx-attributes/on_.mdx delete mode 100644 src/routes/reference/jsx-attributes/once.mdx delete mode 100644 src/routes/reference/jsx-attributes/prop.mdx delete mode 100644 src/routes/reference/jsx-attributes/ref.mdx delete mode 100644 src/routes/reference/jsx-attributes/style.mdx delete mode 100644 src/routes/reference/jsx-attributes/textcontent.mdx delete mode 100644 src/routes/reference/jsx-attributes/use.mdx delete mode 100644 src/routes/reference/lifecycle/on-cleanup.mdx delete mode 100644 src/routes/reference/lifecycle/on-mount.mdx delete mode 100644 src/routes/reference/reactive-utilities/batch.mdx delete mode 100644 src/routes/reference/reactive-utilities/catch-error.mdx delete mode 100644 src/routes/reference/reactive-utilities/create-root.mdx delete mode 100644 src/routes/reference/reactive-utilities/from.mdx delete mode 100644 src/routes/reference/reactive-utilities/get-owner.mdx delete mode 100644 src/routes/reference/reactive-utilities/index-array.mdx delete mode 100644 src/routes/reference/reactive-utilities/map-array.mdx delete mode 100644 src/routes/reference/reactive-utilities/merge-props.mdx delete mode 100644 src/routes/reference/reactive-utilities/observable.mdx delete mode 100644 src/routes/reference/reactive-utilities/on-util.mdx delete mode 100644 src/routes/reference/reactive-utilities/run-with-owner.mdx delete mode 100644 src/routes/reference/reactive-utilities/split-props.mdx delete mode 100644 src/routes/reference/reactive-utilities/start-transition.mdx delete mode 100644 src/routes/reference/reactive-utilities/untrack.mdx delete mode 100644 src/routes/reference/reactive-utilities/use-transition.mdx delete mode 100644 src/routes/reference/rendering/dev.mdx delete mode 100644 src/routes/reference/rendering/hydrate.mdx delete mode 100644 src/routes/reference/rendering/hydration-script.mdx delete mode 100644 src/routes/reference/rendering/is-dev.mdx delete mode 100644 src/routes/reference/rendering/is-server.mdx delete mode 100644 src/routes/reference/rendering/render-to-stream.mdx delete mode 100644 src/routes/reference/rendering/render-to-string-async.mdx delete mode 100644 src/routes/reference/rendering/render-to-string.mdx delete mode 100644 src/routes/reference/rendering/render.mdx delete mode 100644 src/routes/reference/secondary-primitives/create-computed.mdx delete mode 100644 src/routes/reference/secondary-primitives/create-deferred.mdx delete mode 100644 src/routes/reference/secondary-primitives/create-reaction.mdx delete mode 100644 src/routes/reference/secondary-primitives/create-render-effect.mdx delete mode 100644 src/routes/reference/secondary-primitives/create-selector.mdx delete mode 100644 src/routes/reference/server-utilities/get-request-event.mdx delete mode 100644 src/routes/reference/store-utilities/create-mutable.mdx delete mode 100644 src/routes/reference/store-utilities/create-store.mdx delete mode 100644 src/routes/reference/store-utilities/modify-mutable.mdx delete mode 100644 src/routes/reference/store-utilities/produce.mdx delete mode 100644 src/routes/reference/store-utilities/reconcile.mdx delete mode 100644 src/routes/reference/store-utilities/unwrap.mdx delete mode 100644 src/routes/solid-meta/(0)getting-started/(0)installation-and-setup.mdx delete mode 100644 src/routes/solid-meta/(0)getting-started/(1)client-setup.mdx delete mode 100644 src/routes/solid-meta/(0)getting-started/(2)server-setup.mdx delete mode 100644 src/routes/solid-meta/(0)index.mdx delete mode 100644 src/routes/solid-meta/reference/meta/base.mdx delete mode 100644 src/routes/solid-meta/reference/meta/link.mdx delete mode 100644 src/routes/solid-meta/reference/meta/meta.mdx delete mode 100644 src/routes/solid-meta/reference/meta/metaprovider.mdx delete mode 100644 src/routes/solid-meta/reference/meta/style.mdx delete mode 100644 src/routes/solid-meta/reference/meta/title.mdx delete mode 100644 src/routes/solid-meta/reference/meta/use-head.mdx delete mode 100644 src/routes/solid-meta/v1/(0)index.mdx delete mode 100644 src/routes/solid-router/(0)getting-started/(0)installation-and-setup.mdx delete mode 100644 src/routes/solid-router/(0)getting-started/(1)component.mdx delete mode 100644 src/routes/solid-router/(0)getting-started/(2)config.mdx delete mode 100644 src/routes/solid-router/(0)getting-started/(3)linking-routes.mdx delete mode 100644 src/routes/solid-router/(0)index.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(0)navigation.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(1)path-parameters.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(2)search-parameters.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(3)catch-all.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(4)dynamic-routes.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(5)nesting.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(6)layouts.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(7)alternative-routers.mdx delete mode 100644 src/routes/solid-router/(1)concepts/(8)actions.mdx delete mode 100644 src/routes/solid-router/(2)rendering-modes/(0)spa.mdx delete mode 100644 src/routes/solid-router/(2)rendering-modes/(1)ssr.mdx delete mode 100644 src/routes/solid-router/(3)data-fetching/(0)queries.mdx delete mode 100644 src/routes/solid-router/(3)data-fetching/(1)streaming.mdx delete mode 100644 src/routes/solid-router/(3)data-fetching/(2)revalidation.mdx delete mode 100644 src/routes/solid-router/(3)data-fetching/how-to/(0)preload-data.mdx delete mode 100644 src/routes/solid-router/(3)data-fetching/how-to/(1)handle-error-and-loading-states.mdx delete mode 100644 src/routes/solid-router/(4)advanced-concepts/(0)preloading.mdx delete mode 100644 src/routes/solid-router/(4)advanced-concepts/(1)lazy-loading.mdx delete mode 100644 src/routes/solid-router/(5)guides/(0)migration.mdx delete mode 100644 src/routes/solid-router/reference/components/a.mdx delete mode 100644 src/routes/solid-router/reference/components/hash-router.mdx delete mode 100644 src/routes/solid-router/reference/components/memory-router.mdx delete mode 100644 src/routes/solid-router/reference/components/navigate.mdx delete mode 100644 src/routes/solid-router/reference/components/route.mdx delete mode 100644 src/routes/solid-router/reference/components/router.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/action.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/cache.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/create-async-store.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/create-async.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/query.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/revalidate.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/use-action.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/use-submission.mdx delete mode 100644 src/routes/solid-router/reference/data-apis/use-submissions.mdx delete mode 100644 src/routes/solid-router/reference/preload-functions/preload.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-before-leave.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-current-matches.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-is-routing.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-location.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-match.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-navigate.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-params.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-preload-route.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-resolved-path.mdx delete mode 100644 src/routes/solid-router/reference/primitives/use-search-params.mdx delete mode 100644 src/routes/solid-router/reference/response-helpers/json.mdx delete mode 100644 src/routes/solid-router/reference/response-helpers/redirect.mdx delete mode 100644 src/routes/solid-router/reference/response-helpers/reload.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(0)routing.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(1)api-routes.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(2)css-and-styling.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(3)data-fetching.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(4)data-mutation.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(5)head-and-metadata.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(6)route-prerendering.mdx delete mode 100644 src/routes/solid-start/v1/(0)building-your-application/(7)static-assets.mdx delete mode 100644 src/routes/solid-start/v1/(0)index.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(0)middleware.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(1)session.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(2)request-events.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(3)return-responses.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(4)serialization.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(5)auth.mdx delete mode 100644 src/routes/solid-start/v1/(1)advanced/(6)websocket.mdx delete mode 100644 src/routes/solid-start/v1/(1)getting-started.mdx delete mode 100644 src/routes/solid-start/v1/(2)guides/(0)security.mdx delete mode 100644 src/routes/solid-start/v1/(2)guides/(1)data-fetching.mdx delete mode 100644 src/routes/solid-start/v1/(2)guides/(2)data-mutation.mdx delete mode 100644 src/routes/solid-start/v1/(2)guides/(3)service-workers.mdx delete mode 100644 src/routes/solid-start/v1/(2)guides/(4)background-tasks.mdx delete mode 100644 src/routes/solid-start/v1/reference/client/client-only.mdx delete mode 100644 src/routes/solid-start/v1/reference/client/mount.mdx delete mode 100644 src/routes/solid-start/v1/reference/client/start-client.mdx delete mode 100644 src/routes/solid-start/v1/reference/config/define-config.mdx delete mode 100644 src/routes/solid-start/v1/reference/entrypoints/(0)app-config.mdx delete mode 100644 src/routes/solid-start/v1/reference/entrypoints/app.mdx delete mode 100644 src/routes/solid-start/v1/reference/entrypoints/entry-client.mdx delete mode 100644 src/routes/solid-start/v1/reference/entrypoints/entry-server.mdx delete mode 100644 src/routes/solid-start/v1/reference/routing/file-routes.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/create-handler.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/create-middleware.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/get-server-function-meta.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/get.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/http-header.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/http-status-code.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/start-server.mdx delete mode 100644 src/routes/solid-start/v1/reference/server/use-server.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(0)routing.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(1)api-routes.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(2)css-and-styling.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(3)data-fetching.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(4)data-mutation.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(5)head-and-metadata.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(6)route-prerendering.mdx delete mode 100644 src/routes/solid-start/v2/(0)building-your-application/(7)static-assets.mdx delete mode 100644 src/routes/solid-start/v2/(0)index.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(0)middleware.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(1)session.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(2)request-events.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(3)return-responses.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(4)serialization.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(5)auth.mdx delete mode 100644 src/routes/solid-start/v2/(1)advanced/(6)websocket.mdx delete mode 100644 src/routes/solid-start/v2/(1)getting-started.mdx delete mode 100644 src/routes/solid-start/v2/(2)guides/(0)security.mdx delete mode 100644 src/routes/solid-start/v2/(2)guides/(1)data-fetching.mdx delete mode 100644 src/routes/solid-start/v2/(2)guides/(2)data-mutation.mdx delete mode 100644 src/routes/solid-start/v2/(2)guides/(3)service-workers.mdx delete mode 100644 src/routes/solid-start/v2/(2)guides/(4)background-tasks.mdx delete mode 100644 src/routes/solid-start/v2/(2)guides/(5)deployment-plugins.mdx delete mode 100644 src/routes/solid-start/v2/(2)migrating-from-v1.mdx delete mode 100644 src/routes/solid-start/v2/reference/client/client-only.mdx delete mode 100644 src/routes/solid-start/v2/reference/client/mount.mdx delete mode 100644 src/routes/solid-start/v2/reference/client/start-client.mdx delete mode 100644 src/routes/solid-start/v2/reference/config/solid-start.mdx delete mode 100644 src/routes/solid-start/v2/reference/entrypoints/(0)vite-config.mdx delete mode 100644 src/routes/solid-start/v2/reference/entrypoints/app.mdx delete mode 100644 src/routes/solid-start/v2/reference/entrypoints/entry-client.mdx delete mode 100644 src/routes/solid-start/v2/reference/entrypoints/entry-server.mdx delete mode 100644 src/routes/solid-start/v2/reference/routing/file-routes.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/create-handler.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/create-middleware.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/get-server-function-meta.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/get.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/http-header.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/http-status-code.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/start-server.mdx delete mode 100644 src/routes/solid-start/v2/reference/server/use-server.mdx delete mode 100644 src/routes/v2/(0)index.mdx delete mode 100644 src/routes/v2/(1)getting-started.mdx diff --git a/osmium/src/ui/layout/main-header.tsx b/osmium/src/ui/layout/main-header.tsx index 74caa7e59..ee88762a8 100644 --- a/osmium/src/ui/layout/main-header.tsx +++ b/osmium/src/ui/layout/main-header.tsx @@ -88,7 +88,11 @@ export function MainHeader(_props: MainHeaderProps) { - + 1 && project().projects + } + > {(projects) => (
    diff --git a/osmium/src/utils.ts b/osmium/src/utils.ts index 0af8a085e..4f888216f 100644 --- a/osmium/src/utils.ts +++ b/osmium/src/utils.ts @@ -27,10 +27,13 @@ export function useProject() { const projectConfig = config().routes?.project ?? {}; return { - current: useSolidBaseRoute()().project, + current: useSolidBaseRoute()().project ?? "solid", projects: ("values" in projectConfig ? projectConfig.values - : []) as Record, + : { solid: { path: "", label: "Solid" } }) as Record< + string, + { path: string; label: string } + >, }; }); } diff --git a/src/middleware/index.ts b/src/middleware/index.ts index f38296599..f74c40d90 100644 --- a/src/middleware/index.ts +++ b/src/middleware/index.ts @@ -1,6 +1,7 @@ import { createMiddleware } from "@solidjs/start/middleware"; -import { handleLegacyRoutes } from "./legacy-routes-redirect"; +// Legacy URL handling for the 1.x site lives at the edge (and on the v1 +// deployment), not in this app. export default createMiddleware({ - onRequest: [handleLegacyRoutes], + onRequest: [], }); diff --git a/src/middleware/legacy-routes-redirect.ts b/src/middleware/legacy-routes-redirect.ts deleted file mode 100644 index 13e96c53c..000000000 --- a/src/middleware/legacy-routes-redirect.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { redirect } from "@solidjs/router"; -import { type FetchEvent } from "@solidjs/start/server"; - -/** - * Redirect Dictionary - * {origin: destination} - */ -const LEGACY_ROUTES = { - // api reference - "/references/api-reference/basic-reactivity/createEffect": - "/reference/basic-reactivity/create-effect", - "/references/api-reference/basic-reactivity/createMemo": - "/reference/basic-reactivity/create-memo", - "/references/api-reference/basic-reactivity/createResource": - "/reference/basic-reactivity/create-resource", - "/references/api-reference/basic-reactivity/createSignal": - "/reference/basic-reactivity/create-signal", - "/references/api-reference/component-apis/children": - "/reference/component-apis/children", - "/references/api-reference/component-apis/createContext": - "/reference/component-apis/create-context", - "/references/api-reference/component-apis/createUniqueId": - "/reference/component-apis/create-unique-id", - "/references/api-reference/component-apis/lazy": - "/reference/component-apis/lazy", - "/references/api-reference/component-apis/useContext": - "/reference/component-apis/use-context", - "/references/api-reference/control-flow/Dynamic": - "/reference/components/dynamic", - "/references/api-reference/control-flow/ErrorBoundary": - "/reference/components/error-boundary", - "/references/api-reference/control-flow/For": "/reference/components/for", - "/references/api-reference/control-flow/Index": - "/reference/components/index-component", - "/references/api-reference/control-flow/Portal": - "/reference/components/portal", - "/references/api-reference/control-flow/Show": "/reference/components/show", - "/references/api-reference/control-flow/Suspense": - "/reference/components/suspense", - "/references/api-reference/control-flow/SuspenseList": - "/reference/components/suspense-list", - "/references/api-reference/control-flow/Switch-and-Match": - "/reference/components/switch-and-match", - "/references/api-reference/lifecycles/onCleanup": - "/reference/lifecycle/on-cleanup", - "/references/api-reference/lifecycles/onError": - "/reference/reactive-utilities/catch-error", - "/references/api-reference/lifecycles/onMount": - "/reference/lifecycle/on-mount", - "/references/api-reference/reactive-utilities/batch": - "/reference/reactive-utilities/batch", - "/references/api-reference/reactive-utilities/catchError": - "/reference/reactive-utilities/catch-error", - "/references/api-reference/reactive-utilities/createRoot": - "/reference/reactive-utilities/create-root", - "/references/api-reference/reactive-utilities/from": - "/reference/reactive-utilities/from", - "/references/api-reference/reactive-utilities/getOwner": - "/reference/reactive-utilities/get-owner", - "/references/api-reference/reactive-utilities/indexArray": - "/reference/reactive-utilities/index-array", - "/references/api-reference/reactive-utilities/mapArray": - "/reference/reactive-utilities/map-array", - "/references/api-reference/reactive-utilities/mergeProps": - "/reference/reactive-utilities/merge-props", - "/references/api-reference/reactive-utilities/observable": - "/reference/reactive-utilities/observable", - "/references/api-reference/reactive-utilities/on": - "/reference/reactive-utilities/on", - "/references/api-reference/reactive-utilities/regularstartTransition": - "/reference/reactive-utilities/start-transition", - "/references/api-reference/reactive-utilities/runWithOwner": - "/reference/reactive-utilities/run-with-owner", - "/references/api-reference/reactive-utilities/splitProps": - "/reference/reactive-utilities/split-props", - "/references/api-reference/reactive-utilities/untrack": - "/reference/reactive-utilities/untrack", - "/references/api-reference/reactive-utilities/useTransition": - "/reference/reactive-utilities/use-transition", - "/references/api-reference/rendering/DEV": "/reference/rendering/dev", - "/references/api-reference/rendering/hydrate": "/reference/rendering/hydrate", - "/references/api-reference/rendering/HydrationScript": - "/reference/rendering/hydration-script", - "/references/api-reference/rendering/isServer": - "/reference/rendering/is-server", - "/references/api-reference/rendering/render": "/reference/rendering/render", - "/references/api-reference/rendering/renderToStream": - "/reference/rendering/render-to-stream", - "/references/api-reference/rendering/renderToString": - "/reference/rendering/render-to-string", - "/references/api-reference/rendering/renderToStringAsync": - "/reference/rendering/render-to-string-async", - "/references/api-reference/secondary-primitives/createComputed": - "/reference/secondary-primitives/create-computed", - "/references/api-reference/secondary-primitives/createDeferred": - "/reference/secondary-primitives/create-deferred", - "/references/api-reference/secondary-primitives/createReaction": - "/reference/secondary-primitives/create-reaction", - "/references/api-reference/secondary-primitives/createRenderEffect": - "/reference/secondary-primitives/create-render-effect", - "/references/api-reference/secondary-primitives/createSelector": - "/reference/secondary-primitives/create-selector", - "/references/api-reference/special-jsx-attributes/attr_": - "/reference/jsx-attributes/attr", - "/references/api-reference/special-jsx-attributes/classList": - "/reference/jsx-attributes/classlist", - "/references/api-reference/special-jsx-attributes/innerHTML-or-textContent": - "/reference/jsx-attributes/innerhtml", - "/references/api-reference/special-jsx-attributes/on_": - "/reference/jsx-attributes/on_", - "/references/api-reference/special-jsx-attributes/on_-and-oncapture_": - "/reference/jsx-attributes/on", - - "/references/api-reference/special-jsx-attributes/once": - "/reference/jsx-attributes/once", - "/references/api-reference/special-jsx-attributes/prop_": - "/reference/jsx-attributes/prop", - "/references/api-reference/special-jsx-attributes/ref": - "/reference/jsx-attributes/ref", - "/references/api-reference/special-jsx-attributes/style": - "/reference/jsx-attributes/style", - "/references/api-reference/special-jsx-attributes/use_": - "/reference/jsx-attributes/use", - "/references/api-reference/stores/store-utilities": - "/concepts/stores#store-utilities", - "/references/api-reference/stores/using-stores": "/concepts/stores", - - // deployment - "/guides/how-to-guides/deployment": "/guides/deploying-your-app", - "/guides/how-to-guides/deployment/deploying-to-cloudflare": - "/guides/deployment-options/cloudflare", - "/guides/how-to-guides/deployment/deploying-to-firebase": - "/guides/deployment-options/firebase", - "/guides/how-to-guides/deployment/deploying-to-flightcontrol": - "/guides/deployment-options/aws-via-flightcontrol", - "/guides/how-to-guides/deployment/deploying-to-netlify": - "/guides/deployment-options/netlify", - "/guides/how-to-guides/deployment/deploying-to-railway": - "/guides/deployment-options/railway", - "/guides/how-to-guides/deployment/deploying-to-vercel": - "/guides/deployment-options/vercel", - - // styling - "/guides/how-to-guides/styling-in-solid": "/guides/styling-your-components", - "/guides/how-to-guides/styling-in-solid/sass": - "/guides/styling-components/sass", - "/guides/how-to-guides/styling-in-solid/less": - "/guides/styling-components/less", - "/guides/how-to-guides/styling-in-solid/tailwind-css": - "/guides/styling-components/tailwind", - "/guides/how-to-guides/styling-in-solid/css-modules": - "/guides/styling-components/css-modules", - "/guides/how-to-guides/styling-in-solid/unocss": - "/guides/styling-components/uno", - - // trailing slash removal - "/routing/migration/": "/routing/migration", - "/concepts/refs/": "/concepts/refs", - "/guides/state-management/": "/guides/state-management", - - // miscellaneous - "/guides/foundations/typescript-for-solid": "/configuration/typescript", - "/guides/foundations/understanding-components": "/concepts/components/basics", - "/guides/foundations/why-solid": "/#advantages-of-using-solid", - "/guides/how-to-guides/routing-in-solid/solid-router": - "/routing/installation-and-setup", - "/guides/tutorials/getting-started-with-solid/installing-solid": - "/quick-start", - "/references/concepts/reactivity": "/concepts/intro-to-reactivity", - "/references/concepts/reactivity/tracking": - "/concepts/intro-to-reactivity#subscribers", - "/references/concepts/ssr/async-ssr": "/guides/fetching-data", - "/references/concepts/ssr/simple-client-fetching-ssr": - "/guides/fetching-data", - "/references/concepts/state-management/context": - "/guides/complex-state-management#state-sharing", - - // solid-docs-next moves/new location for old pages/solid api updates - "/reference/jsx-attributes/on-and-oncapture": "/reference/jsx-attributes/on", - - "/solid-router/reference/response-helpers/revalidate": - "/solid-router/reference/data-apis/revalidate", - - "/solid-start/guides/data-loading": "/solid-start/v1/guides/data-fetching", -} as const; - -const SOLID_START_PATH = "/solid-start"; -const SOLID_START_VERSIONED_ROUTE = /^\/solid-start\/v\d+(?:\/|$)/; - -function isLegacyRoute(path: string): path is keyof typeof LEGACY_ROUTES { - return path in LEGACY_ROUTES; -} - -export const handleLegacyRoutes = (event: FetchEvent) => { - const { pathname } = new URL(event.request.url); - - if (isLegacyRoute(pathname)) { - return redirect(LEGACY_ROUTES[pathname], 301); - } - - if (pathname === SOLID_START_PATH || pathname === `${SOLID_START_PATH}/`) { - return redirect( - `${SOLID_START_PATH}/v2${pathname.endsWith("/") ? "/" : ""}`, - 301 - ); - } - - if ( - pathname.startsWith(`${SOLID_START_PATH}/`) && - !SOLID_START_VERSIONED_ROUTE.test(pathname) - ) { - return redirect( - `${SOLID_START_PATH}/v1${pathname.slice(SOLID_START_PATH.length)}`, - 301 - ); - } -}; diff --git a/src/routes/(0)concepts/(0)components/(0)basics.mdx b/src/routes/(0)concepts/(0)components/(0)basics.mdx deleted file mode 100644 index 42fb44cbd..000000000 --- a/src/routes/(0)concepts/(0)components/(0)basics.mdx +++ /dev/null @@ -1,312 +0,0 @@ ---- -title: Basics -category: Concepts / Components -order: 4 -use_cases: >- - starting new projects, creating components, understanding component structure, - building ui blocks, component organization -tags: - - components - - basics - - jsx - - lifecycle - - imports - - structure -version: "1.0" -description: >- - Learn Solid component fundamentals: creating reusable UI blocks, component - trees, lifecycles, and proper import/export patterns. ---- - -Components are the building blocks of Solid applications. -These units are reusable and can be combined to create more complex applications. - -Components are functions that return [JSX](/concepts/understanding-jsx) elements: - -```tsx -function MyComponent() { - return
    Hello World
    ; -} -``` - -A component can be as simple as a single element or as complex as a full page. -They can also be nested within each other to create more intricate applications: - -```tsx -function App() { - return ( -
    - -
    - ); -} -``` - -:::note - -Component names must start with a capital letter to distinguish them from regular HTML elements. -Otherwise, they won't be recognized as components. - -::: - -## Component trees - -A web page is displayed by rendering a component tree, which is a hierarchical structure of components. -At the top of the tree is the primary application component, which is the root of the tree. -Child components are nested within the primary component, and those components can have their own child components. -This nesting can continue as needed. - -A simple application may have a component tree that looks like this: - -```json -App // primary application component -└── MyComponent // child component -``` - -When an application grows, the component tree can become more complex. -For example, a more complex application may have a component tree that looks like this: - -```json -App -├── Header -├── Sidebar -├── Content -│ ├── Post -│ │ ├── PostHeader -│ │ ├── PostContent -│ │ └── PostFooter -│ ├── Post -│ │ ├── PostHeader -│ │ ├── PostContent -│ │ └── PostFooter -│ └── Post -│ ├── ... -└── Footer -``` - -In nesting components, you can create a hierarchy of components that can be reused throughout the application. -This allows for a more modular approach to building applications, as components can be reused in different contexts. - -## Component lifecycles - -Components have a lifecycle that defines how they are created, updated, and destroyed. -A Solid component's lifecycle is different from other frameworks, as it is tied to the [concept of reactivity](/concepts/intro-to-reactivity). - -Where frameworks may re-run components on every state change, a Solid component's lifecycle is tied to its initial run. -What this means is that a Solid component is only run once, when it is first rendered into the DOM. -After that, the component is not re-run, even if the application's state changes. - -When the Solid component renders, it sets up a reactive system that monitors for state changes. -When a state change occurs, the component will update the relevant areas without re-running the entire component. -By bypassing the full component lifecycle on every state change, Solid has a more predictable behavior compared to frameworks that re-run functions on every update. - -Since the component's logic is not continuously visited, getting this setup right is important when working with Solid. - -### Initialization & configuration - -When a component is first rendered into the DOM, the component function is executed. -This is where you will set up the component's state and side-effects. -This includes setting up [signals](/concepts/signals), [stores](/concepts/stores), [effects](/concepts/effects), and other reactive elements. -Since the logic in the component function is not continuously visited, it is important to set up the component correctly from the outset. - -Each component instance is independent of other instances, meaning that each component has its own state and side-effects. -Through establishing proper dependencies, you can ensure that the component is set up correctly. -This allows for components to be reused in different contexts without affecting each other. - -```tsx -function MyComponent() { - const [count, setCount] = createSignal(0); - - console.log(count()); - - return ( -
    -

    Count: {count()}

    - -
    - ); -} -``` - -When this component is rendered into the DOM, the function body is executed. -This includes creating the `count` signal and executing the `console.log(count())` statement, which will log the current value of `count` to the console. -In addition, the component's JSX is returned, which will be rendered into the DOM. - -After the component is rendered, the `console.log` statement will not be executed again, even if the component's state changes. -However, because the component's JSX is reactive, each press of the button will update the DOM with the new value of `count`. - -In essence, Solid splits the concerns: - -1. The initial setup logic, which is executed once when the component is rendered. -2. The reactive logic, which is executed when the component's state changes. - -### Conditional rendering - -To display different content based on state or other criteria, you can use conditional rendering. -Given that the component function is only executed once, conditional statements must be placed within the return statement. -This design ensures that conditional paths are clear and immediately understood. - -```tsx -function MyComponent() { - const [count, setCount] = createSignal(0); - return ( -
    - {count() > 5 ? ( -
    Count limit reached
    - ) : ( - <> -

    Count: {count()}

    - - - )} -
    - ); -} -``` - -This example uses a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator) to conditionally render different content based on the value of `count`. -When `count` is greater than 5, the component will display `"Count limit reached"`. -Otherwise, it will display the current count with an increment button. - -:::note -To simplify conditional rendering, Solid provides built-in [control-flow](/concepts/control-flow/conditional-rendering) components like [`Show`](/concepts/control-flow/conditional-rendering#show), which create a more readable conditional rendering experience. - - ```tsx - function MyComponent() { - const [count, setCount] = createSignal(0) - - return ( -
    - 5} - fallback={ - <> -

    Count: {count()}

    - - - } - > -
    Count limit reached
    -
    -
    - ) - } - ``` - -::: - -## Importing and exporting - -For components to be reusable, they need to be exported from one module and imported into another. -This allows for components to be shared and used where needed. - -### Exporting components - -Once defined, a component can be [exported](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export) to make it available for use in other parts of your application. -There are two ways to export a component: [named exports](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export#named_exports) and [default exports](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export#default_exports). - -**Named export:** - -Named exports allow for multiple components to be exported from a single file. -To export a component, you must use the `export` keyword before the function definition or specify the name of the component to export in curly braces (`{}`). - -```typescript -export function MyComponent() { - return
    Hello World
    -} - -// or - -function MyComponent() { - return
    Hello World
    -} - -export { MyComponent } -``` - -**Default export:** - -Default exports specify a single component to export from a file. -This is done by using the `default` keyword. - -```typescript -// MyComponent.ts -export default function MyComponent() { - return
    Hello World
    -} -``` - -### Importing components - -To use a component in another file or component, it must be [imported](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import). -To import a component, you must specify the path to the file containing the component and the name of the component to import. - -**Named import:** - -When importing a named export, you must specify the name of the component to import in curly braces (`{}`). - -```tsx -// App.ts -import { MyComponent } from "./MyComponent"; - -function App() { - return ( -
    - -
    - ); -} -``` - -This is the preferred way to import components, as it allows for better code readability and maintainability. -Additionally, it allows for multiple components to be imported from the same file. - -```tsx -// App.ts -import { MyComponent, MyOtherComponent } from "./MyComponent"; - -function App() { - return ( -
    - - -
    - ); -} -``` - -**Default import:** - -To import a default export, you must specify the name of the component to import. - -```tsx -// App.ts -import MyComponent from "./MyComponent"; - -function App() { - return ( -
    - -
    - ); -} -``` - -### Importing Solid and its utilities - -To use Solid, you must import the Solid library. -The reactive primitives and utilities are exported from Solid's main module. - -```tsx -import { createSignal } from "solid-js"; -``` - -However, some of Solid's utilities are exported from their own modules. - -```tsx -import { createStore } from "solid-js/store"; -``` - -To see a full list of Solid's utilities, the Reference Tab in the sidebar provides the API Documentation. diff --git a/src/routes/(0)concepts/(0)components/(1)class-style.mdx b/src/routes/(0)concepts/(0)components/(1)class-style.mdx deleted file mode 100644 index bad4b6334..000000000 --- a/src/routes/(0)concepts/(0)components/(1)class-style.mdx +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Class and style -category: Concepts / Components -order: 2 -use_cases: >- - styling components, dynamic theming, conditional styling, css integration, - responsive design, ui customization -tags: - - styling - - css - - classes - - themes - - dynamic - - ui -version: "1.0" -description: >- - Style Solid components with CSS classes and inline styles. Learn dynamic - styling, classList usage, and theme implementation. ---- - -Similar to HTML, Solid uses `class` and `style` attributes to style elements via [CSS (Cascading Style Sheets)](https://developer.mozilla.org/en-US/docs/Glossary/CSS). - -- **Class attribute**: Enables styling one or more elements through CSS rules. -- **Style attribute**: Inline styles that style single elements. - -## Inline styling - -The `style` attribute allows you to style a single element and define CSS variables dynamically during runtime. -To use it, you can pass either a string or an object. - -```tsx -// String -
    This is a red div
    - -// Object -
    This is a red div
    -``` - -When using an object, the keys represent the CSS property names, and the values represent the CSS property values. -The keys must be in dash-case, and the values must be strings. - - - -While inline styles are useful for rapid prototyping, they are not recommended for production use. -This is because they are not reusable, and they can be difficult to maintain over time. - -## Classes - -The `class` attribute allows you to style one or more elements through CSS rules. -This provides a more structured approach to styling, as it allows you to reuse styles across multiple elements. - -Classes are defined in CSS files. You can import these files using the `import` statement at the top of your component file. -The CSS file's contents will be inserted into a style tag in the document head. - -```jsx -import "./Card.css"; - -function Card() { - // ... -} -``` - -### Dynamic styling - -Dynamic styling provides a way to change the appearance of a component based on state or other factors like user inputs. -This is useful for creating components that can adapt to different scenarios without having to create multiple versions of the same component: - -```tsx -const [theme, setTheme] = createSignal("light"); - -
    - This div's theme is determined dynamically! -
    ; -``` - -[Props](/concepts/components/props) are another way to change styles. -By passing props to components, you can adapt styles based on the component's usage or the data it receives: - -```tsx -function ThemedButton(props) { - return ( - - ); -} -``` - -### `classList` - -When you want to apply multiple classes to an element, you can use the [`classList` attribute](https://developer.mozilla.org/en-US/docs/Web/API/Element/classList). -To use it, you can pass either a string or an object where the keys represent the class names and the values represent a boolean expression. -When the value is `true`, the class is applied; when `false`, it is removed. - -```tsx -const [current, setCurrent] = createSignal("foo"); - -; -``` - -`classList` is often more efficient than `class` when handling multiple conditional classes. -This is because `classList` selectively toggles only the classes that require alteration, while `class` will be re-evaluated each time. -For a single conditional class, using `class` might be simpler but as the number of conditional classes increases, `classList` offers a more readable and declarative approach. - -:::note -While it is possible, mixing `class` and `classList` can introduce unexpected errors. -If both are reactive when the `class` value changes, Solid will set the entire `class` attribute. -This will remove any classes set by `classList`. - - To avoid this, the `class` attribute should be set to a static string or nothing. - Alternatively, `class` can be set to a static computed value (e.g. `class={baseClass()}`), but then it must be put before any `classList` attributes. - - Additionally, since `classList` is a pseudo-attribute, it doesn't work in prop spreads like `
    ` or in ``. - -::: - -For a guide on how to style your components, see [Styling Your Components](/guides/styling-your-components), where we cover the different ways to style your components using libraries such as [Tailwind CSS](https://tailwindcss.com/). diff --git a/src/routes/(0)concepts/(0)components/(2)props.mdx b/src/routes/(0)concepts/(0)components/(2)props.mdx deleted file mode 100644 index 4e8f892ef..000000000 --- a/src/routes/(0)concepts/(0)components/(2)props.mdx +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: Props -category: Concepts / Components -use_cases: >- - passing data between components, parent-child communication, component - configuration, default values, prop management -tags: - - props - - components - - data - - communication - - mergeprops - - splitprops -version: "1.0" -description: >- - Pass and manage component props in Solid while maintaining reactivity. Learn - mergeProps, splitProps, and best practices. ---- - -Props are a way to pass state from a parent component to a child component. -These read-only properties are passed to components as attributes within JSX and are accessible within the component via the `props` object: - -```tsx -function App() { - // Passing a prop named "name" to the MyComponent component - return ( -
    - -
    - ); -} -``` - -To access the props in the child component, you use the `props` object: - -```tsx -function MyComponent(props) { - return
    Hello {props.name}
    ; -} -``` - -## `mergeProps` - -[`mergeProps`](/reference/reactive-utilities/merge-props) is a Solid utility function designed to merge multiple potentially reactive objects together. -It behaves similar to [`Object.assign`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) but will retain the reactivity of the properties being merged. -This helps ensure that when individual properties within the merged object change, their reactivity is not lost. - -```typescript -import { mergeProps } from "solid-js"; - -function MyComponent(props) { - // Using mergeProps to set default values for props - const finalProps = mergeProps({ defaultName: "Ryan Carniato" }, props); - - return
    Hello {finalProps.defaultName}
    ; -} - -// Usage: -``` - -When merging props, if there is no existing value for a property, the value from the first object will be used. -However, if a value already exists, it will be used instead, all while retaining the reactivity of the property. - -## Destructuring props - -Props are read-only so that child components do not directly modify the data passed by the parent. -This also encourages one-way data flow, a pattern often seen to promote more predictable data management. - -With Solid, destructuring props is not recommended as it can break reactivity. -Instead, you should access props directly from the `props` object, or wrap them in a function to ensure they are always up-to-date: - -```typescript -function MyComponent(props) { - const { name } = props; // ❌: breaks reactivity and will not update when the prop value changes - const name = props.name; // ❌: another example of breaking reactivity - const name = () => props.name; // ✓: by wrapping `props.name` into a function, `name()` always retrieves its current value -} -``` - -### `splitProps` - -[`splitProps`](/reference/reactive-utilities/split-props) is a utility function designed to help split a single props object into multiple sets of props, retaining the reactivity of the individual properties. -It provides a way to destructure props without breaking reactivity. - -`splitProps` gives you the ability to define one or more arrays of keys that you wish to extract into separate props objects, all while retaining the reactivity of the individual properties. -It will return an array of props objects related to each set of keys, plus an additional props object containing any remaining keys. - -When passing props to child components, you can use `splitProps` to split the props into multiple groups, and then pass each group to the appropriate child component: - -```typescript -import { splitProps } from "solid-js"; - -function ParentComponent(props) { - // Splitting props into two groups: 'name' and 'age' - const [greetingProps, personalInfoProps, restProps] = splitProps( - props, - ["name"], - ["age"] - ); - - // Using greetingProps and personalInfoProps in the current component - return ( -
    - - - {/* restProps can be passed down or used as needed */} -
    - ); -} -``` - -## Passing props to children - -In most instances, simply using `props` within JSX will work without any issues. -However, there are some cases where accessing `props.children` multiple times can introduce problems and unexpected behaviours, such as repeated creation of child components or elements. -For instances like these, Solid provides a [`children`](/reference/component-apis/children) helper that ensures you always get the right child components without anything unwanted happening. - -```typescript -import { children } from "solid-js"; - -function ColoredList(props) { - const safeChildren = children(() => props.children); - - return <>{safeChildren()}; -} -``` - -## Prop drilling - -Prop drilling refers to passing props through multiple layers of components. -While this is a valid pattern, it can cause props to become cluttered and confusing -in larger component trees, especially when intermediate components receive values they do not directly use. - -When multiple components across different levels need access to the same data, Solid’s [Context](/concepts/context) API provides a cleaner alternative. [Context](/concepts/context) allows you to supply values to deeply nested components without manually threading props through each layer. diff --git a/src/routes/(0)concepts/(0)components/(3)event-handlers.mdx b/src/routes/(0)concepts/(0)components/(3)event-handlers.mdx deleted file mode 100644 index 6e75e7b0a..000000000 --- a/src/routes/(0)concepts/(0)components/(3)event-handlers.mdx +++ /dev/null @@ -1,233 +0,0 @@ ---- -title: Event handlers -category: Concepts / Components -order: 3 -use_cases: >- - user interactions, click handling, form inputs, keyboard events, custom - events, touch gestures, event optimization -tags: - - events - - interactions - - handlers - - delegation - - performance - - dom -version: "1.0" -description: >- - Handle user interactions in Solid with event delegation and native events for - optimal performance and resource management. ---- - -Event handlers are functions that are called in response to specific events occurring in the browser, such as when a user clicks or taps on an element. - -Solid provides two ways to add event listeners to the browser: - -- [`on:__`](/reference/jsx-attributes/on): adds an event listener to the `element`. This is also known as a _native event_. -- [`on__`](/reference/jsx-attributes/on_): adds an event listener to the `document` and dispatches it to the `element`. This can be referred to as a _delegated event_. - -Delegated events conserve resources and improve performance for commonly used events by sharing a single handler. -Native events, conversely, offer greater control over event behavior. - -## Using events - -To add an event handler, prefix the event name with either `on` or `on:`, and assign it to the function you wish to call when the event is dispatched. - -```tsx -// delegated event - - -// native event -
    ... very long text ...
    -``` - -Delegated events are **not case sensitive**, therefore using delegated event handlers in Solid can be written using camelCase or all lowercase. -Note that while delegated events can be written both ways, native events _are_ case sensitive. - -```tsx - -``` - -For any other events, such as custom events or events you wish _not_ to be delegated, the `on:` attribute will add an event listener as-is. -This is what makes the event listener case sensitive. - -```tsx - -``` - -For typing standard or custom events using `on:`, the TypeScript page has a section about [event handlers](/configuration/typescript#event-handling). - -## Binding events - -To optimize event handlers, you can pass an array as the event handler, replacing the function. -When doing this, the second item passed into the array is supplied as the handler's first argument: - -```tsx -const handler = (data, event) => { - console.log("Data:", data, "Event:", event); -}; - -; -``` - -In this example, the `Hello!` string is passed as the `data` parameter in the `handler` function when the button is clicked. - -By binding events in this way, Solid avoids the overhead of using JavaScript's [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) method and adding an additional closure. - -### Dynamic handlers - -An event handler does not form part of the reactive system. -If you were to pass the handler as a signal, it will not respond to the changes of that signal. -In other words, events do not dynamically update, and the bindings are not reactive. -This is because attaching and detaching listeners is a resource-intensive task. - -Since event handlers are called like a standard function, you can design them to call a reactive source, if needed. - -In the following example, `handleClick` represents a prop that has the flexibility to adopt any function. -As a result, there is no requirement for these functions to be reactive. - -```tsx -
    props.handleClick?.()} /> -``` - -## Event delegation - -Instead of attaching event listeners to every individual element, Solid uses _synthetic event delegation_, through the [`on__`](/reference/jsx-attributes/on_) form . -In this method, event listeners are attached to the `document` element and dispatch events to the relevant elements as they bubble up. - -By keeping the number of event listeners to a minimum, events can be captured more effectively. -This is especially useful when working with a large number of elements, such as in a table or list. - -Supported events such as `click`, `input` and `keydown` are just a few examples that are optimized in this way. -To view the full list see the [references below](#list-of-delegated-events). - -If you need to attach an event listener to an element that is not supported by Solid's event delegation, such as a custom event in a [custom element](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements), you can use the [`on:__`](/reference/jsx-attributes/on) form. - -```tsx -
    -``` - -### Event delegation considerations - -While delegated events provide some performance enhancements, there are tradeoffs. - -Delegated events flow through native element parents but can be overriden by components like Portal. -This can differ from the previous expectations of how events work and flow. - -Some things to keep in mind include: - -- Delegated event listeners are added _once_ per event type and handle all future events of that type. - This means that delegated event listeners remain active even if the element that added them and its handler is removed. - For example, if a `div` listens for `mousemove` and is later removed, the `mousemove` events will still be dispatched to the `document` in case a different element is also listening for mouse moves. - -```tsx -
    -``` - -:::tip[Occasional Events] - -Rather than using delegated events for events that happen infrequently, **native events** are a better solution. -Since these events happen in specific circumstances, they do not benefit from the performance improvements you get with event delegation. - -```tsx -
    -``` - -::: - -- `event.stopPropagation()` does not work as expected since events are attached to the `document` rather than the `element`. - - With cases like this, a native event is recommended. - As an example, using a native event would stop the following event from reaching the `div native` handler, which is _not_ the case for delegated events. - You can [view this example in the Solid Playground](https://playground.solidjs.com/anonymous/c5346f84-01e4-4080-8ace-4443ffd0bb10). - -```tsx -onMount(() => { - ref.addEventListener("click", () => { - console.log("div native"); - }); -}); -
    - -
    ; -``` - -```shellsession title="Console output" -// Button clicked -div native -button -``` - -You can solve this by switching the `button` event to using a native event: - -```tsx ins="on:click" -// ... - -// ... -``` - -```shellsession title="Console output" -// Button clicked -button -``` - -[See how this solution differs in the Solid Playground](https://playground.solidjs.com/anonymous/9e2deddc-2e83-4ac2-8ee0-49c7c3a45d11). - -- [Portals](/concepts/control-flow/portal) propagate events following the _component tree_ and not the _DOM tree_, making them easier to use. - This means when a `Portal` gets attached to the `body`, any events will propagate up to the `container`. - -```tsx -
    console.log("portal key press")}> - - console.log("input key press")} /> - -
    -``` - -:::note[onInput / onChange] - - `onChange` and `onInput` events work according to their native behavior: - - `onInput` will fire immediately after the value has changed - - In `` fields, `onChange` will only fire after the field loses focus. - -::: - -### List of delegated events - -You can also view this list in our [source code](https://github.com/ryansolid/dom-expressions/blob/main/packages/dom-expressions/src/constants.js) (see `DelegatedEvents`). - -- [`beforeinput`](https://developer.mozilla.org/en-US/docs/Web/API/Element/beforeinput_event) -- [`click`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click) -- [`dblclick`](https://developer.mozilla.org/en-US/docs/Web/API/Element/dblclick_event) -- [`contextmenu`](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event) -- [`focusin`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusin_event) -- [`focusout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/focusout_event) -- [`input`](https://developer.mozilla.org/en-US/docs/Web/API/Element/input_event) -- [`keydown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/keydown_event) -- [`keyup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/keyup_event) -- [`mousedown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mousedown_event) -- [`mousemove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mousemove_event) -- [`mouseout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseout_event) -- [`mouseover`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseover_event) -- [`mouseup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseup_event) -- [`pointerdown`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerdown_event) -- [`pointermove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event) -- [`pointerout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerout_event) -- [`pointerover`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerover_event) -- [`pointerup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerup_event) -- [`touchend`](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchend_event) -- [`touchmove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchmove_event) -- [`touchstart`](https://developer.mozilla.org/en-US/docs/Web/API/Element/touchstart_event) diff --git a/src/routes/(0)concepts/(0)intro-to-reactivity.mdx b/src/routes/(0)concepts/(0)intro-to-reactivity.mdx deleted file mode 100644 index 94ff0a6dc..000000000 --- a/src/routes/(0)concepts/(0)intro-to-reactivity.mdx +++ /dev/null @@ -1,264 +0,0 @@ ---- -title: Intro to reactivity -category: Concepts -order: 1 -use_cases: >- - learning reactivity, understanding signals, reactive principles, state - management basics, getting started -tags: - - reactivity - - signals - - fundamentals - - state - - subscribers - - basics -version: "1.0" -description: >- - Master Solid's reactive system fundamentals: signals, subscribers, and - automatic UI updates for responsive applications. ---- - -**Note**: While this guide is useful for understanding reactive systems, it does use some Solid-specific terminology. - -Reactivity powers the interactivity in Solid applications. -This programming paradigm refers to a system's ability to respond to changes in data or state automatically. -With Solid, reactivity is the basis of its design, ensuring applications stay up-to-date with their underlying data. - -## Importance of reactivity - -1. Reactivity keeps the user interface (UI) and state in sync, which reduces the need for manual updates. - -2. Real-time updates create a more responsive and interactive user experience. - -```jsx -function Counter() { - const [count, setCount] = createSignal(0); - const increment = () => setCount((prev) => prev + 1); - - return ( -
    - Count: {count()}{" "} - {/* Only `count()` is updated when the button is clicked. */} - -
    - ); -} -``` - -This `Counter` function sets up a button that, when clicked, calls the `increment` function to increase the `count` by one. -This updates just the number displayed _without_ refreshing the entire component. - - - -## Reactive principles - -### Signals - -Signals serve as core elements in reactive systems, playing an important role in data management and system responsiveness. -They are responsible for storing and managing data, as well as triggering updates across the system. -This is done through the use of getters and setters. - -```jsx -const [count, setCount] = createSignal(0); -// ^ getter ^ setter -``` - - - -- **Getter**: A function responsible for accessing the current value of the signal. - You call a getter to access the data stored in a signal within a component. - -- **Setter**: - The function used to modify a signal's value. - To trigger reactive updates across an application, you call a setter to update the value of a signal. - -```js -console.log(count()); // `count()` is a getter that returns the current value of `count`, which is `0`. - -setCount(1); // the setter, `setCount`, updates the value of `count`. - -console.log(count()); // the updated value of `count` is now `1`. -``` - -### Subscribers - -Subscribers are the other core element in reactive systems. -They are responsible for tracking changes in signals and updating the system accordingly. -They are automated responders that keep the system up-to-date with the latest data changes. - -Subscribers work based on two main actions: - -- **Observation**: At their core, subscribers observe signals. - This keeps the subscriber primed to pick up on any changes to the signal they are tracking. -- **Response**: When a signal changes, the subscriber is notified. - This triggers the subscriber to respond to the change in the signal. - This can involve tasks like updating the UI or calling external functions. - -```jsx -function Counter() { - const [count, setCount] = createSignal(0); - const increment = () => setCount((prev) => prev + 1); - - createEffect(() => { - console.log(count()); - }); - // the `createEffect` will trigger the console log every time `count` changes. -} -``` - -## State management - -State management is the process of managing the state of an application. -This involves storing and updating data, as well as responding to the changes in it. - -With Solid, state management is handled through signals and subscribers. -Signals are used to store and update data, while subscribers are used to respond to changes in the data. - -### Tracking changes - -Tracking changes involves monitoring any updates to the data and responding accordingly. -This is done through the use of subscribers. - -When a signal is not accessed within a tracking scope, an update to the signal will not trigger an update. -This happens because if a signal is not being tracked, it is not able to notify any subscribers of the change. - -```jsx -const [count, setCount] = createSignal(0); - -console.log("Count:", count()); - -setCount(1); - -// Output: Count: 0 - -// `count` is not being tracked, so the console log will not update when `count` changes. -``` - -Initialization, or creation is a **one-time event** that doesn't cause tracking. -To track a signal, it must be accessed within the scope of a subscriber. -Reactive primitives, such as [memos](/concepts/derived-values/memos) can be used to create derived values from signals or other memos, and [effects](/concepts/effects) to create subscribers that use the reactive graph output once it's settled. - -```jsx -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log("Count:", count()); -}); - -setCount(1); - -// Output: Count: 0 -// Count: 1 -``` - -### Updating the UI - -The UI of a Solid application is built using [JSX](/concepts/understanding-jsx). -JSX creates a tracking scope behind the scenes, which allows signals to be tracked within the return statement of a component. - -```jsx -function Counter() { - const [count, setCount] = createSignal(0); - const increment = () => setCount((prev) => prev + 1); - - return ( -
    - Count: {count()}{" "} - {/* ✅ will update when `count()` changes. */} - -
    - ); -} -``` - -Components, much like other functions, will only run _once_. -This means that if a signal is accessed outside of the return statement, it will run on initialization, but any updates to the signal will not trigger an update. - -```jsx -function Counter() { - const [count, setCount] = createSignal(0); - const increment = () => setCount((prev) => prev + 1); - - console.log("Count:", count()); // ❌ not tracked - only runs once during initialization. - - createEffect(() => { - console.log(count()); // ✅ will update whenever `count()` changes. - }); - - return ( -
    - Count: {count()} - {/* ✅ will update whenever `count()` changes. */} - -
    - ); -} -``` - -To learn more about managing state in Solid, visit the [guide on state management](/guides/state-management). - -## Synchronous vs. asynchronous - -Reactive systems are designed to respond to changes in data. -These responses can be immediate or delayed, depending on the nature of the system. -Often, the choice between these two depends on the requirements of the application and the nature of the tasks involved. - -### Synchronous reactivity - -[Synchronous](https://developer.mozilla.org/en-US/docs/Glossary/Synchronous) reactivity is Solid's default reactivity mode, where a system responds to changes in a direct and linear fashion. -When a signal changes, any corresponding subscribers are immediately updated in an ordered manner. - -With synchronous reactivity, the system is able to respond to changes in a predictable manner. -This is useful in scenarios where the order of updates is important. -For example, if a subscriber depends on another signal, it is important that the subscriber is updated after the signal it depends on. - -```jsx -const [count, setCount] = createSignal(0); -const [double, setDouble] = createSignal(0); - -createEffect(() => { - setDouble(count() * 2); -}); -``` - -In this example, the `double` signal will always be updated after `count` due to synchronous reactivity. -This ensures that `double` is always up-to-date with the latest value of `count`. - -### Asynchronous reactivity - -[Asynchronous](https://developer.mozilla.org/en-US/docs/Glossary/Asynchronous) reactivity is when a system responds to changes in a delayed or non-linear fashion. -When a signal changes, the corresponding subscribers are not immediately updated. -Instead, the system waits for a specific event or task to complete before updating the subscribers. - -This is important in scenarios where subscribers depend on multiple signals. -In these cases, updating one signal before another could result in data inconsistency. -For example, if a subscriber depends on two signals, it is important that the subscriber is updated after both signals have been updated. -Rather, the system waits for both signals to be updated before updating the subscriber. - -**Note:** When asynchronous reactivity is present, it is important to ensure that the system is able to handle the delay in updates. -[`batch`](/reference/reactive-utilities/batch) can be used to delay an update so the subscriber runs after each signal has been updated. - -## Key concepts - -- Signals are the core elements of a reactive system. - They are responsible for storing and managing data. -- Signals are both readable and writeable because of getters and setters. -- Subscribers are automated responders that track changes in signals and update the system accordingly. -- Signals and subscribers work together to ensure that the system is kept up-to-date with the latest data changes. -- A reactive system is built on the principles of data-driven reactivity. - This means that the system's reactivity is driven by the data it is built on. -- Reactive systems can be synchronous or asynchronous. - -If you want to dive deeper, visit the [guide on fine-grained reactivity](/advanced-concepts/fine-grained-reactivity). diff --git a/src/routes/(0)concepts/(1)control-flow/(0)conditional-rendering.mdx b/src/routes/(0)concepts/(1)control-flow/(0)conditional-rendering.mdx deleted file mode 100644 index f5228cc4e..000000000 --- a/src/routes/(0)concepts/(1)control-flow/(0)conditional-rendering.mdx +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: Conditional rendering -category: Concepts / Control Flow -order: 1 -use_cases: >- - showing/hiding content, loading states, error displays, user permissions, - dynamic ui, feature toggles -tags: - - conditional - - rendering - - show - - switch - - match - - ui -version: "1.0" -description: >- - Conditionally render UI elements in Solid using Show, Switch, and Match - components for clean, readable conditional logic. ---- - -Conditional rendering is the process of displaying different UI elements based on certain conditions. -This is a common pattern in UI development, and is often used to show or hide elements based on user input, data, or other conditions. - -Solid offers dedicated components to handle conditional rendering in a more straightforward and readable way. - -## Show - -[``](/reference/components/show) renders its children when a condition is evaluated to be true. -Similar to the [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) in JavaScript, it uses control logic flow within JSX to determine what to render. - -`` has a `when` property that is used to determine whether or not to render its children. -When there is a change in the state or props it depends on, this property is re-evaluated. -This property can be a boolean value, or a function that returns a boolean value. - -```jsx -import { Show } from "solid-js"; - - -
    Loading...
    -
    ; -``` - -`` has the `fallback` property that can be used to specify the content to be rendered when the condition evaluates to false. -This property can return a JSX element. - -```jsx -import { Show } from "solid-js"; - -Loading...
    }> -

    Hi, I am {data().name}.

    -; -``` - -If there are multiple conditions that need to be handled, `` can be nested to handle each condition. - -```jsx -import { Show } from "solid-js"; - - -
    Loading...
    - -
    Error: {data.error}
    -
    -
    ; -``` - -## Switch and Match - -When there are multiple conditions that need to be handled, it can be difficult to manage the logic flow with nested `` components. -Solid has the `` and `` components for this purpose. - -Similar to JavaScript's [switch/case](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch) structure, `` wraps multiple `` components so that each condition is evaluated _in sequence_. -The first `` component that evaluates to true will have its children rendered, and the rest will be ignored. - -```jsx -import { Switch, Match } from "solid-js"; - - - -

    Outcome 1

    -
    - -

    Outcome 2

    -
    -
    ; -``` - -Similar to ``, each `` component has a `when` property that is used to determine whether or not to render its children. -An optional `fallback` property can also be passed to `` to specify the content be rendered when none of the `` components evaluate to true. - -```jsx -import { Switch, Match } from "solid-js"; - -Fallback content

    }> - -

    Outcome 1

    -
    - -

    Outcome 2

    -
    -
    ; -``` diff --git a/src/routes/(0)concepts/(1)control-flow/(1)list-rendering.mdx b/src/routes/(0)concepts/(1)control-flow/(1)list-rendering.mdx deleted file mode 100644 index 8317c42ed..000000000 --- a/src/routes/(0)concepts/(1)control-flow/(1)list-rendering.mdx +++ /dev/null @@ -1,169 +0,0 @@ ---- -title: List rendering -category: Concepts / Control Flow -order: 3 -use_cases: >- - rendering arrays, dynamic lists, data iteration, tables, repeating elements, - collection display, performance optimization -tags: - - lists - - arrays - - for - - index - - iteration - - rendering - - performance -version: "1.0" -description: >- - Efficiently render dynamic lists in Solid using For and Index components. - Optimize performance for different data scenarios. ---- - -List rendering allows you to generate multiple elements from a collection of data, such as an array or object, where each element corresponds to an item in the collection. - -When dealing with dynamic data, Solid offers two ways to render lists: the [``](/reference/components/for) and `` components. -Both of these components help you loop over data collections to generate elements, however, they both cater to different scenarios. - -## `` - -`` is a looping component that allows you to render elements based on the contents of an array or object. -This component is designed to be used with **complex data structures**, such as arrays of objects, where the order and length of the list may change frequently. - -The sole property in `` is `each` , through which you can specify the data collection to loop over. -This property expects an array, however, it can also accept objects that have been converted to arrays using utilities such as [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) or [`Object.values`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values). - -```jsx -import { For } from "solid-js" - - - {(item, index) => - // rendering logic for each element - } - -``` - -Between the `` tags, the component requires a [callback function](https://developer.mozilla.org/en-US/docs/Glossary/Callback_function) which will dictate how each item in the data collection should be rendered. -This structure resembles the callback used within JavaScript's [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) method, providing a familiar pattern to follow. - -The function receives two arguments: - -- `item`: represents the current item in the data collection that is being rendered over. -- `index`: the current item's index within the collection. - -You can access the current `item` and `index` to dynamically set attributes or content of the JSX elements. -Index is a [_signal_](/concepts/signals) and must be called as a function to retrieve its value. - -```jsx - - {(item, index) => ( -
  • - {item.name} -
  • - )} -
    -``` - -## `Index` - -``, similar to ``, is a looping component that allows you to render elements based on the contents of an array or object. -However, when the order and length of the list remain _stable_, but the content may change frequently, `` is a better option because it results in fewer re-renders. - -```jsx -import { Index } from "solid-js" - - - {(item, index) => ( - // rendering logic for each element - )} - -``` - -Similar to the `` component, `` accepts a single property named `each`, which is where you pass the structure you wish to loop over. - -Where the `index` is a signal with ``, it remains fixed with ``. -This is because `` is more concerned with the **index** of the elements in the array. -Because of this, the `item` is a signal, allowing the _content_ at each index to change without a re-render while the index remains fixed. - -```jsx -import { Index } from "solid-js"; - - - {(item, index) => ( -
  • - {item().name} - {item().completed} -
  • - )} -
    ; -``` - -## `` vs `` - -`` is designed to be used when the _order_ and _length_ of the list may change frequently. -When the list value changes in ``, the entire list is re-rendered. -However, if the array undergoes a change, such as an element shifting position, `` will manage this by simply **moving** the corresponding DOM node and **updating** the index. - -``, however, is designed to be used when the **order** and **length** of the list remain _stable_, but the content may change frequently. -When the list value changes in ``, only the content at the specified index is updated. - -### When to use `` - -In cases where signals, nested loops, or dynamic lists are not required, `` is the best option. -For example, when creating a list of static elements, such as a list of links, `` is the best option to use. -This is because it will only modify the indexes of the elements in the list, rather than re-rendering the entire list. - -```jsx -import { createSignal, For } from "solid-js"; - -function StringList() { - const [items, setItems] = createSignal(["Item 1", "Item 2", "Item 3"]); - - return ( -
      - { - // add the new item to the list - }} - /> - - {(item, index) => ( -
    • - {item} - {index()} -
    • - )} -
      -
    - ); -} -``` - -If you are working with signals, [JavaScript primitives like strings and numbers](https://developer.mozilla.org/en-US/docs/Glossary/Primitive) or input fields, `` is the better option to use. -If you were using ``, the entire list would be re-rendered when a value changes, even if the length of the list remains unchanged. -``, instead, will update the content at the specified index, while the rest of the list remains unchanged. - -```jsx -import { createSignal, Index } from "solid-js"; - -function FormList() { - const [inputs, setInputs] = createSignal(["input1", "input2", "input3"]); - return ( -
    - - {(input, index) => ( - { - // update the input value - }} - /> - )} - -
    - ); -} -``` diff --git a/src/routes/(0)concepts/(1)control-flow/(2)dynamic.mdx b/src/routes/(0)concepts/(1)control-flow/(2)dynamic.mdx deleted file mode 100644 index cc6465e23..000000000 --- a/src/routes/(0)concepts/(1)control-flow/(2)dynamic.mdx +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: Dynamic -category: Concepts / Control Flow -order: 2 -use_cases: >- - dynamic component selection, polymorphic components, runtime component - switching, flexible ui rendering, component factories -tags: - - dynamic - - components - - rendering - - polymorphic - - runtime - - flexible -version: "1.0" -description: >- - Render components dynamically at runtime with Solid's Dynamic component. Build - flexible UIs with runtime component selection. ---- - -[``](/reference/components/dynamic) is a Solid component that allows you to render components dynamically based on data. -By passing either a string representing a [native HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) or a component function to the `component` prop, you can render the chosen component with the remaining props you provide. - -```jsx -import { createSignal, For } from "solid-js"; -import { Dynamic } from "solid-js/web"; - -const RedDiv = () =>
    Red
    ; -const GreenDiv = () =>
    Green
    ; -const BlueDiv = () =>
    Blue
    ; - -const options = { - red: RedDiv, - green: GreenDiv, - blue: BlueDiv, -}; - -function App() { - const [selected, setSelected] = createSignal("red"); - - return ( - <> - - - - ); -} -``` - -This example renders a ` setSelected(e.currentTarget.value)} - > - - {(color) => } - - - }> - - - - - - - - - ); -} -``` - -Instead of a more verbose [`` and ``](/concepts/control-flow/conditional-rendering) statement, `` offers a more concise way to render components dynamically. - -## Props - -When working with these components, you can pass [props](/concepts/components/props) to the component you are rendering by passing them to the `` component. -This makes them available to the component you are rendering, similar to how you would pass props to components in JSX. - -```jsx -import { Dynamic } from "solid-js/web"; - -function App() { - return ; -} -``` diff --git a/src/routes/(0)concepts/(1)control-flow/(3)error-boundary.mdx b/src/routes/(0)concepts/(1)control-flow/(3)error-boundary.mdx deleted file mode 100644 index 200163f67..000000000 --- a/src/routes/(0)concepts/(1)control-flow/(3)error-boundary.mdx +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Error boundary -category: Concepts / Control Flow -order: 5 -use_cases: >- - error handling, crash prevention, user-friendly errors, app stability, error - recovery, debugging production issues -tags: - - errors - - boundary - - handling - - recovery - - stability - - debugging -version: "1.0" -description: >- - Catch and handle rendering errors gracefully with ErrorBoundary. Prevent app - crashes and provide user-friendly error recovery. ---- - -By default, if part of an application throws an error during rendering, the entire application can crash, resulting in Solid removing its UI from the screen. -Error boundaries provide a way to catch these errors and prevent the entire app from crashing. - -The [``](/reference/components/error-boundary) component is used to create an error boundary. -It catches any error that occurs during the rendering or updating of its children. -However, an important note is that errors occurring outside the rendering process, such as in event handlers or after a `setTimeout`, are _not_ caught by error boundaries. - -The `fallback` prop can be used to display a user-friendly error message or notification when an error occurs. -If a function is passed to `fallback`, it will receive the error object as well as a `reset` function. -The `reset` function forces the `` to re-render its children and reset the error state, providing users with a way to recover from the error. - -```tsx -import { ErrorBoundary } from "solid-js"; -import { Header, ErrorProne } from "./components"; - -function App() { - return ( -
    -
    - ( -
    -

    Something went wrong: {error.message}

    - -
    - )} - > - -
    -
    - ); -} -``` - -In this example, when the `ErrorProne` component throws an error, the `` catches it, preventing it from affecting the rest of the application. -Instead, it displays the error message passed to the fallback prop. diff --git a/src/routes/(0)concepts/(1)control-flow/(4)portal.mdx b/src/routes/(0)concepts/(1)control-flow/(4)portal.mdx deleted file mode 100644 index 4e5c0ef99..000000000 --- a/src/routes/(0)concepts/(1)control-flow/(4)portal.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Portal -category: Concepts / Control Flow -order: 3 -use_cases: >- - modals, popups, tooltips, dropdowns, z-index issues, overflow clipping, - rendering outside parent container -tags: - - portal - - modal - - popup - - dom - - z-index - - overflow -version: "1.0" -description: >- - Learn how Portal renders elements outside the normal DOM flow to solve z-index - and overflow issues for modals and popups. ---- - -When an element requires rendering outside of the usual document flow, challenges related to stacking contents and z-index can interfere with the desired intention or look of an application. -[``](/reference/components/portal) helps with this by putting elements in a different place in the document, bringing an element into the document flow so it can render as expected. - -```jsx -import { Portal } from "solid-js/web"; - - - -; -``` - -The content nested within `` is rendered and positioned by default at the end of the document body. - - - -This can be changed by passing a `mount` prop to ``. -The `mount` prop accepts a [DOM node](https://developer.mozilla.org/en-US/docs/Web/API/Node), which will be used as the mount point for the portal content. - -```jsx -import { Portal } from "solid-js/web"; - - - -; -``` - -Using `` can be particularly useful in cases where elements, like information popups, might be clipped or obscured due to the overflow settings of their parent elements. -By putting the element outside of the parent element, it is no longer bound by the overflow settings of its parent. -This creates a more accessible experience for users, as the content is no longer obscured. - -:::note -`` will render wrapped unless specifically targeting `document.head`. - -This is so events propagate through the Portal according to the component hierarchy instead of the elements hierarchy. - -By default, children will wrap in a `
    `. If you portal into an SVG, then the `isSVG` prop must be used to avoid wrapping the children in a `
    ` and wrap in a `` instead. - -```jsx -import { Portal } from "solid-js/web"; - -function Rect() { - return ( - - - - ); -} - -function SVG() { - return ; -} -``` - -::: diff --git a/src/routes/(0)concepts/(1)understanding-jsx.mdx b/src/routes/(0)concepts/(1)understanding-jsx.mdx deleted file mode 100644 index e36299791..000000000 --- a/src/routes/(0)concepts/(1)understanding-jsx.mdx +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: Understanding JSX -category: Concepts -order: 2 -use_cases: >- - writing components, html in javascript, dynamic content, templating, props - passing, event handling -tags: - - jsx - - components - - templates - - props - - html - - syntax -version: "1.0" -description: >- - Write HTML-like syntax in JavaScript with JSX to create reactive components - with dynamic expressions and event handlers. ---- - -JSX is an extension for JavaScript. -It allows you to write HTML-like code inside your JavaScript file which keeps your rendering logic and content in the same place. -This provides a concise and readable way to create and represent components. - -## How Solid uses JSX - -Solid was designed to align closely with HTML standards. - -```jsx -const element =

    I'm JSX!!

    ; -``` - -It offers a distinct advantage, however: to copy/paste solutions from resources like Stack Overflow; and to allow direct usage of templates from design tools. -Solid sets itself apart by using JSX immediately as it returns [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction) elements. -This lets you use dynamic expressions within your HTML by allowing variables and functions to be referenced with the use of curly braces (`{ }`): - -```jsx -const Component = () => { - const animal = { breed: "cat", name: "Midnight" }; - - return ( -

    - I have a {animal.breed} named {animal.name}! -

    - ); -}; -``` - -This means JavaScript content can be rendered on web pages based on an application's state or logic. - -Additionally, Solid's [reactive](/concepts/intro-to-reactivity) system introduces [fine-grained reactivity](/advanced-concepts/fine-grained-reactivity) with JSX. -This updates only the necessary parts of the DOM when changes occur in the underlying state. - -## Using JSX in Solid - -### Return a single root element - -Where HTML lets you have disconnected tags at the top level, JSX requires that a component return a single root element. - -:::advanced -When working with JSX, parts of your code are translated into structured HTML that is placed at the start of the file. -Static elements are processed differently from dynamic ones, which might change based on data or user actions. -For dynamic elements, special markers are added for better handling during rendering. - -Having a single root creates a consistent and manageable hierarchy to optimize rendering and updates. -::: - -JSX maintains the familiar nested, tree-like structure found in HTML. -As a result, parent-child relationships between elements become easier to follow. - -### Close all tags - -Self-closing tags are a must in JSX. -Unlike in HTML, where elements like ``, ``, or `
    ` don't require explicit closure, JSX requires consistent self-closing tags. -This helps to avoid potential rendering issues. - -```jsx - -``` - -### Properties vs. attributes - -HTML attributes and JSX properties may seem similar, but they serve different purposes and behave differently. -Both offer ways to specify configurations or pass information. -However, HTML is used for standard web content and JSX creates Solid's component logic. - -#### HTML attributes - -[HTML attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes) are values set directly on HTML elements. -They provide additional information about an element to guide its initial behavior and state. -These attributes are often translated into properties on DOM objects once the browser parses the HTML. - -In JSX files, HTML attributes are used much like regular HTML, with a few key differences due to the blend of HTML and JavaScript: - -- Event listeners such as `onClick` can be in camelCase or lowercase. - (**Note:** When using ESLint, you will get a warning if you use lowercase.) -- In cases where you can dynamically specify a value, you can replace the `"` and `"` with curly braces (`{ }`): - -```jsx - -``` - - :::note - If you wish to pass objects in JSX, such as with inline styling, you will have to use double curly braces (`{{ }}`). - -```jsx - -``` - -::: - -### JSX properties (props) - -JSX properties, commonly known as "props," help with the passing of data and configurations to components within an application. -They connect the component with the data it requires, for seamless data flows and dynamic interactions. - -#### Core concepts - -- **Static props**: - In Solid's JSX, static props are integrated directly into the HTML by cloning the template and using them as attributes. - -- **Dynamic props**: - Dynamic props rely on state, allowing the content or properties to be dynamic. - An example is changing the style of an element in response to interactions within an application. - This can be expressed in the form of signals (`value={value()}`). - -- **Data transfer**: - Props are also used to fill components with data that comes from resources, like [`createResource`](/reference/basic-reactivity/create-resource) calls. - This results in components that react in real-time to data changes. - -:::note -Expressions, whether fixed or dynamic, get applied _in the order defined within the JSX_. -This works for a wide range of DOM elements, but will not work with elements that require attributes to be defined in a special order, such as input types with `type='range'`. - -When order influences an element's behavior, users must define the expressions in the order that the element is expected. -::: - -For how to use props effectively in Solid, explore the [props page](/concepts/components/props). diff --git a/src/routes/(0)concepts/(2)derived-values/(0)derived-signals.mdx b/src/routes/(0)concepts/(2)derived-values/(0)derived-signals.mdx deleted file mode 100644 index 146bce522..000000000 --- a/src/routes/(0)concepts/(2)derived-values/(0)derived-signals.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Derived signals -category: Concepts / Derived Values -order: 1 -use_cases: >- - computed values, reactive calculations, dependent state, dynamic values from - signals -tags: - - signals - - reactivity - - derived - - computed - - state -version: "1.0" -description: >- - Create reactive derived values that automatically update when their - dependencies change using Solid's derived signals. ---- - -Derived signals are functions that rely on one or more [signals](/concepts/signals) to produce a value. - -These functions are not executed immediately, but instead are only called when the values they rely on are changed. -When the underlying signal is changed, the function will be called again to produce a new value. - -```js -const double = () => count() * 2; -``` - -In the above example, the `double` function relies on the `count` signal to produce a value. -When the `count` signal is changed, the `double` function will be called again to produce a new value. - -Similarly you can create a derived signal that relies on a store value because stores use signals under the hood. -To learn more about how stores work, [you can visit the stores section](/concepts/stores). - -```js -const fullName = () => store.firstName + " " + store.lastName; -``` - -These dependent functions gain reactivity from the signal they access, ensuring that changes in the underlying data propagate throughout your application. -It is important to note that these functions do not store a value themselves; instead, they can update any effects or components that depend on them. -If included within a component's body, these derived signals will trigger an update when necessary. - -While you can create derived values in this manner, Solid created the [`createMemo`](/reference/basic-reactivity/create-memo) primitive. -To dive deeper into how memos work, [check out the memos section](/concepts/derived-values/memos). diff --git a/src/routes/(0)concepts/(2)derived-values/(1)memos.mdx b/src/routes/(0)concepts/(2)derived-values/(1)memos.mdx deleted file mode 100644 index cb19920e5..000000000 --- a/src/routes/(0)concepts/(2)derived-values/(1)memos.mdx +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: Memos -category: Concepts / Derived Values -order: 2 -use_cases: >- - expensive computations, caching results, optimizing performance, derived - state, avoiding re-calculations -tags: - - memo - - performance - - caching - - optimization - - reactivity - - computed -version: "1.0" -description: >- - Optimize expensive computations with memos that cache results and only - recalculate when dependencies actually change. ---- - -Memos are a type of reactive value that can be used to memoize derived state or expensive computations. -They are similar to [derived signals](/concepts/derived-values/derived-signals) in that they are reactive values that automatically re-evaluate when their dependencies change. -However, unlike derived signals, memos are optimized to execute only once for each change in their dependencies. - -Memos expose a _read-only_ reactive value (like a [signal](/concepts/signals)) and track changes in their dependencies (similar to an [effect](/concepts/effects)). -This makes them useful for caching the results of expensive or frequently accessed computations. -By doing this, memos minimize unnecessary work within an application by retaining the results of a computation until its dependencies change. - -## Using memos - -A memo is created using the `createMemo` function. -Within this function, you can define the derived value or computations you wish to memoize. -When called, `createMemo` will return a **getter** function that reads the current value of the memo: - -```jsx -import { createMemo, createSignal } from "solid-js"; - -const [count, setCount] = createSignal(0); - -const isEven = createMemo(() => count() % 2 === 0); - -console.log(isEven()); // true - -setCount(3); -console.log(isEven()); // false -``` - -While memos look similar to effects, they are different in that they _return a value_. -This value is the result of the computation or derived state that you wish to memoize. - -### Advantages of using memos - -While you can use a [derived signal](/concepts/derived-values/derived-signals) to achieve similar results, memos offer distinct advantages: - -- Memos are optimized to execute only once for each change in their dependencies. -- When working with expensive computations, memos can be used to cache the results so they are not recomputed unnecessarily. -- A memo will only recompute when its dependencies change, and will not trigger subsequent updates (as determined by [`===` or strict equality](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality)) if its dependencies change but its value remains the same. -- Any signal or memo accessed within a memo's function is **tracked**. - This means that the memo will re-evaluate automatically when these dependencies change. - - - -## Memo vs. effect - -Both memos and effects are important when managing reactive computations and side effects. -They, however, serve different purposes and each has their own unique behaviors. - -| | Memos | Effects | -| -------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -| Return value | Yes - returns a getter for the result of the computation or derived state. | Does not return a value but executes a block of code in response to changes. | -| Caches results | Yes | No | -| Behavior | Function argument should be pure without reactive side effects. | Function argument can cause side effects like UI updates or data fetches. | -| Dependency tracking. | Yes | Yes | -| Example use cases | Transforming data structures, computing aggregated values, derived state, or other expensive computations. | UI updates, network requests, or external integrations. | - -## Best practices - -### Pure functions - -When working with memos, it is recommended that you leave them "pure". - -```jsx -import { createSignal, createMemo } from "solid-js"; - -const [count, setCount] = createSignal(0); -const isEven = createMemo(() => count() % 2 === 0); // example of a pure function -``` - -A pure function is one that does not cause any side effects. -This means that the function's output should solely depend on its inputs. - -When you introduce side effects into a memo, it can complicate the reactivity chain. -This can lead to unexpected behavior, such as infinite loops, that lead your application to crash. - -```jsx -import { createSignal, createMemo } from "solid-js"; - -const [count, setCount] = createSignal(0); -const [message, setMessage] = createSignal(""); - -const badMemo = createMemo(() => { - if (count() > 10) { - setMessage("Count is too high!"); // side effect - } - return count() % 2 === 0; -}); -``` - -These infinite loops can be triggered when a memo has a side effect that causes its dependencies to change. -This will cause the memo to re-evaluate, which will then trigger the side effect again, and so on until the application crashes. - -This can be avoided by using a [`createEffect`](/reference/basic-reactivity/create-effect) to handle the side effects instead: - -```jsx -import { createSignal, createMemo, createEffect } from "solid-js"; - -const [count, setCount] = createSignal(0); -const [message, setMessage] = createSignal(""); - -const isEven = createMemo(() => count() % 2 === 0); - -createEffect(() => { - if (count() > 10) { - setMessage("Count is too high!"); - } -}); -``` - -Here, the `createEffect` will handle the side effects, while the `isEven` memo will remain pure. - -### Keep logic in memos - -Memos are optimized to execute only once for each change in their dependencies. -This means that you can remove unnecessary effects that are triggered by a memo's dependencies. - -When working with derived state, memos are the recommended approach over effects. -Keeping the logic in a memo prevents unnecessary re-renders that can occur when using an effect. -Similarly, effects are better suited to handle side effects, such as DOM updates, rather than derived state. -This separation of concerns can help keep your code clean and easy to understand. - -```jsx -// effect - runs whenever `count` changes -createEffect(() => { - if (count() > 10) { - setMessage("Count is too high!"); - } else { - setMessage(""); - } -}); - -// memo - only runs when `count` changes to or from a value greater than 10 -const message = createMemo(() => { - if (count() > 10) { - return "Count is too high!"; - } else { - return ""; - } -}); -``` diff --git a/src/routes/(0)concepts/(2)signals.mdx b/src/routes/(0)concepts/(2)signals.mdx deleted file mode 100644 index 0eca59676..000000000 --- a/src/routes/(0)concepts/(2)signals.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: Signals -category: Concepts -order: 2 -use_cases: >- - state management, reactive values, component state, updating ui, tracking - changes, basic reactivity -tags: - - signals - - state - - reactivity - - getter - - setter - - fundamentals -version: "1.0" -description: >- - Create reactive state with signals - the foundation of Solid's reactivity - system for automatic UI updates and tracking. ---- - -Signals are the primary means of [managing state](/concepts/intro-to-reactivity#state-management) in your Solid application. -They provide a way to store and update values, and are the foundation of [reactivity](/concepts/intro-to-reactivity) in Solid. - -Signals can be used to represent any kind of state in your application, such as the current user, the current page, or the current theme. -This can be any value, including primitive values such as strings and numbers, or complex values such as objects and arrays. - -## Creating a signal - -You can create a signal by calling the [`createSignal`](/reference/basic-reactivity/create-signal) function, which is imported from `solid-js`. -This function takes an initial value as an argument, and returns a pair of functions: a **getter** function, and a **setter** function. - -```jsx -import { createSignal } from "solid-js"; - -const [count, setCount] = createSignal(0); -// ^ getter ^ setter -``` - - :::note - The syntax using `[` and `]` is called [array destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). - -This lets you extract values from the array. -In the context of `createSignal`, the first value is the getter function, and the second value is the setter function. - -::: - -## Accessing values - -The getter function returned by `createSignal` is used to access the value of the signal. -You call this function with no arguments to get the current value of the signal: - -```jsx -console.log(count()); // output: 0 -``` - -## Updating values - -The setter function returned by `createSignal` is used to update the value of the signal. -This function takes an argument that represents the new value of the signal: - -```jsx -setCount(count() + 1); - -console.log(count()); // output: 1 -``` - -The setter function can also take a function that passes the previous value. - -```jsx -setCount((prevCount) => prevCount + 1); - -console.log(count()); // output: 1 -``` - -## Reactivity - -Signals are reactive, which means that they automatically update when their value changes. -When a signal is called within a [tracking scope](/concepts/intro-to-reactivity#tracking-changes), the signal adds the dependency to a list of subscribers. -Once a signal's value changes, it notifies all of its dependencies of the change so they can re-evaluate their values and update accordingly. - -```jsx -function Counter() { - const [count, setCount] = createSignal(0); - const increment = () => setCount((prev) => prev + 1); - - return ( -
    - Count: {count()} {/* Updates when `count` changes */} - -
    - ); -} -``` - -:::note -A tracking scope can be created by [`createEffect`](/reference/basic-reactivity/create-effect) or [`createMemo`](/reference/basic-reactivity/create-memo), which are other Solid primitives. - -Both functions subscribe to the signals accessed within them, establishing a dependency relationship. -Once this relationship is established, the function is notified whenever the signal changes. - -::: - -To learn more about how to use Signals in your application, visit our [state management guide](/guides/state-management). diff --git a/src/routes/(0)concepts/(3)effects.mdx b/src/routes/(0)concepts/(3)effects.mdx deleted file mode 100644 index 26283d3d8..000000000 --- a/src/routes/(0)concepts/(3)effects.mdx +++ /dev/null @@ -1,213 +0,0 @@ ---- -title: Effects -category: Concepts -order: 4 -use_cases: >- - side effects, dom manipulation, api calls, subscriptions, logging, reacting to - state changes -tags: - - effects - - side-effects - - reactivity - - lifecycle - - subscriptions -version: "1.0" -description: >- - Manage side effects like DOM updates, API calls, and subscriptions that - respond automatically to reactive state changes. ---- - -Effects are functions that are triggered when the signals they depend on change. -They play a crucial role in managing side effects, which are actions that occur outside of the application's scope, such as DOM manipulations, data fetching, and subscriptions. - -## Using an effect - -An effect is created using the `createEffect` function. -This function takes a callback as its argument that runs when the effect is triggered. - -```jsx -import { createEffect } from "solid-js"; - -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log(count()); -}); -``` - -In this example, an effect is created that logs the current value of `count` to the console. -When the value of `count` changes, the effect is triggered, causing it to run again and log the new value of `count`. - -:::note -Effects are primarily intended for handling side effects that do not write to the reactive system. -It's best to avoid setting signals within effects, as this can lead to additional rendering or even infinite loops if not managed carefully. -Instead, it is recommended to use [createMemo](/reference/basic-reactivity/create-memo) to compute new values that rely on other reactive values. -::: - -## Managing dependencies - -Effects can be set to observe any number of dependencies. -Dependencies are what allow an effect to track changes and respond accordingly. -These can include signals, props, context, or any other reactive values. -When any of these change, the effect is notified and will run again to update its state. - -Upon initialization, an effect will run _once_, regardless of whether it has any dependencies. -This is useful for setting up the effect and initializing variables or subscribing to [signals](/concepts/signals). -After this run, the effect will only be triggered when any of its _dependencies_ change. - -```jsx -createEffect(() => { - console.log("hello"); // will run only once -}); - -createEffect(() => { - console.log(count()); // will run every time count changes -}); -``` - -Solid automatically tracks the dependencies of an effect, so you do not need to manually specify them. -This improves the tracking and minimizes the chances of overlooking or incorrectly identifying dependencies. - -## Subscribing to signals - -When an effect is set to observe a signal, it creates a subscription to it. -This subscription allows the effect to track the changes in the signal's value, which causes it to observe any changes that may happen and to execute its callback accordingly. - -```jsx -import { createSignal, createEffect } from "solid-js"; - -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log(count()); // Logs current value of count whenever it changes -}); -``` - -### Managing multiple signals - -Effects have the ability to observe multiple signals. -A single effect can subscribe to multiple signals, and similarly, multiple effects can keep track of a single signal. -This is useful when you need to update the UI based on multiple signals. - -When multiple signals are observed within a single effect, it will execute its callback whenever _any_ of the signals change. -The effect will run even if only one of the signals changes, not necessarily all of them. -This means that the effect will run with the latest values of all of the signals that it is observing. - -```jsx -import { createSignal, createEffect } from "solid-js"; - -const [count, setCount] = createSignal(0); -const [message, setMessage] = createSignal("Hello"); - -createEffect(() => { - console.log(count(), message()); -}); - -setCount(1); // Output: 1, "Hello" -setMessage("World"); // Output: 1, "World" -``` - -:::note -When a signal updates, it notifies all of its subscribers sequentially but the _order can vary_. -While effects are guaranteed to run when a signal updates, the execution might **not** be instantaneous. -This means that the order of execution of effects is _not guaranteed_ and should not be relied upon. -::: - -### Nested effects - -When working with effects, it is possible to nest them within each other. -This allows each effect to independently track its own dependencies, without affecting the effect that it is nested within. - -```jsx -createEffect(() => { - console.log("Outer effect starts"); - createEffect(() => console.log("Inner effect")); - console.log("Outer effect ends"); -}); -``` - -The order of execution is important to note. -An inner effect will _not_ affect the outer effect. -Signals that are accessed within an inner effect, will _not_ be registered as dependencies for the outer effect. -When the signal located within the inner effect changes, it will trigger only the _inner effect_ to re-run, not the outer one. - -```jsx -import { createSignal, createEffect } from "solid-js"; - -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log("Outer effect starts"); - createEffect(() => console.log(count())); // when count changes, only this effect will run - console.log("Outer effect ends"); -}); -``` - -This forces each effect to be independent of each other, which helps to avoid unexpected behaviour. -Additionally, it allows you to create effects that are only triggered when certain conditions are met. - -## Lifecycle functions - -Effects have a lifecycle that can be managed using certain functions. -These functions allow you to control the initialization and disposal of effects to build the type of behaviour that you need. -This can include running a side effect only once, or cleaning up a task when it is no longer needed. - -### `onMount` - -In situations where you just want to run a side effect **once**, you can use the [`onMount`](/reference/lifecycle/on-mount) function. -This lifecycle function is similar to an effect, but it does not track any dependencies. -Rather, once the component has been initialized, the `onMount` callback will be executed and will not run again. - -```jsx -import { onMount, createEffect, createSignal } from "solid-js"; - -function Component() { - const [data, setData] = createSignal(null); - - createEffect(() => { - data(); // will run every time data changes - }); - - onMount(async () => { - // will run only once, when the component is mounted - const fetchedData = await fetch("https://example.com/data"); - setData(fetchedData); - }); - - return
    ...
    ; -} -``` - -`onMount` provides the assurance that the callback will only run once. -If using an effect in this situation, there is no guarantee that it will only run once, which can lead to unexpected behaviour. -This makes `onMount` useful for API calls and other side effects that only need to be run once per component instance. - -### `onCleanup` - -While `onMount` is useful for running a side effect once, [`onCleanup`](/reference/lifecycle/on-cleanup) is helpful for cleaning up a task when it is no longer needed. -`onCleanup` will run whenever the component unmounts, removing any subscriptions that the effect has. - -```jsx -import { onCleanup, createSignal } from "solid-js"; - -function App() { - const [count, setCount] = createSignal(0); - - const timer = setInterval(() => { - setCount((prev) => prev + 1); - }, 1000); - - onCleanup(() => { - clearInterval(timer); - }); - - return
    Count: {count()}
    ; -} -``` - -In this example, the `onCleanup` function is used to clear the interval that is set up in the effect. -To avoid the interval from running indefinitely, the `onCleanup` function is used to clear the interval once the component unmounts. - -`onCleanup` can be used to avoid memory leaks. -These occur when a component is unmounted, but references to it still exist and, as a result, could still be running in the background. -Using `onCleanup` to remove any subscriptions or references to the component can help to avoid this issue. diff --git a/src/routes/(0)concepts/(4)context.mdx b/src/routes/(0)concepts/(4)context.mdx deleted file mode 100644 index 393ee8e67..000000000 --- a/src/routes/(0)concepts/(4)context.mdx +++ /dev/null @@ -1,278 +0,0 @@ ---- -title: Context -category: Concepts -order: 5 -use_cases: >- - global state management, avoiding prop drilling, theme providers, - authentication state, shared data across components -tags: - - context - - state - - global - - providers - - sharing - - management -version: "1.0" -description: >- - Share data across component trees with Solid's Context API. Avoid prop - drilling and manage global application state effectively. ---- - -Context provides a way to pass data through the component tree without having to pass props down manually at every level. - -## When to use context - -When you have a large [component tree](/concepts/components/basics#component-trees) that requires state to be shared, context can be used. -Context can be employed to avoid [prop drilling](/concepts/components/props#prop-drilling), which is the practice of passing props through intermediate elements without using them directly. - -If you want to avoid passing some props through a few layers, when applicable, adjusting your component hierarchy may be an easier solution. -[Signals](/concepts/signals) are often the simplest solution since they can be imported directly into the components that need them. - -Context, however, is designed to share data that is global to an application or for information that is regularly accessed by multiple components in an application's component tree. -This offers a way to access state across an application without passing props through intermediate layers or importing them directly into components. - -## Creating context - -Context is created using the [`createContext`](/reference/component-apis/create-context) function. -This function has a `Provider` property that wraps the component tree you want to provide context to. - -```jsx tab title="/context/create.js" -import { createContext } from "solid-js"; - -export const MyContext = createContext(); -``` - -```jsx tab title="/context/component.jsx" -import { MyContext } from "./create"; - -export function Provider(props) { - return {props.children}; -} -``` - -## Providing context to children - -To pass a value to the `Provider`, you use the `value` prop which can take in any value, including [signals](#updating-context-values). -Once a value is passed to the `Provider`, it is available to all components that are descendants of the `Provider`. - -When passing a single value, it can be directly passed to the `value` prop: - -```jsx title="/context/component.jsx" -import { createContext, useContext } from "solid-js"; -import { MyContext } from "./create"; - -const Provider = (props) => ( - {props.children} -); -``` - -:::tip[Complex Types] -When passing multiple values (as an `array` or `object`), it is recommended to use a [store](/reference/component-apis/create-context#usage). -::: - -## Consuming context - -Once the values are available to all the components in the context's component tree, they can be accessed using the [`useContext`](/reference/component-apis/use-context) utility. -This utility takes in the context object and returns the value(s) passed to the `Provider`: - -```jsx title="/context/component.jsx" -import { createContext, useContext } from "solid-js"; -import { MyContext } from "./create"; - -const Provider = (props) => ( - {props.children} -); - -const Child = () => { - const value = useContext(MyContext); - - return {value}; -}; - -export const App = () => ( - - - -); -``` - -## Customizing Context Utilities - -When an application contains multiple context objects, it can be difficult to keep track of which context object is being used. -To solve this issue, you can create a custom utility to create a more readable way to access the context values. - -For example, when wrapping a component tree, you may want to create a custom `Provider` component that can be used to wrap the component tree. -This also provides you with the option of re-using the `Provider` component in other parts of your application, if needed. - -```jsx -import { createSignal, createContext, useContext } from "solid-js"; -import { CounterContext } from "~/context/counter"; - -export function CounterProvider(props) { - return ( - - {props.children} - - ); -} -``` - -Now if you had to access the Provider in different areas of your application, you can simply import the `CounterProvider` component and wrap the component tree: - -```jsx -import { CounterProvider } from "./counterProvider"; - -export function App() { - return ( - -

    Welcome to Counter

    - -
    - ); -} -``` - -Similarly, you can create a custom utility to access the context values. -Instead of importing `useContext` and passing in the context object on each component that you're using it in, creating a customized utility can make it easier to access the values you need: - -```jsx -export function useCounter() { - return useContext(CounterContext); -} -``` - -The `useCounter()` utility in this example can now be imported into any component that needs to access the context values: - -```jsx -import { useCounter } from "./counter"; - -export function CounterProvider(props) { - const count = useCounter(); - return ( - <> -
    {count()}
    - - ); -} -``` - -## Updating Context Values - -[Signals](/concepts/signals) offer a way to synchronize and manage data shared across your components using context. -You can pass a signal directly to the `value` prop of the `Provider` component, and any changes to the signal will be reflected in all components that consume the context. - -```jsx tab title="App.jsx" -import { CounterProvider } from "./Context"; -import { Child } from "./Child"; - -export function App() { - return ( - -

    Welcome to Counter App

    - -
    - ); -} -``` - -```jsx tab title="Context.jsx" -import { createSignal, useContext } from "solid-js"; - -export function CounterProvider(props) { - const [count, setCount] = createSignal(props.initialCount || 0); - const counter = [ - count, - { - increment() { - setCount((prev) => prev + 1); - }, - decrement() { - setCount((prev) => prev - 1); - }, - }, - ]; - - return ( - - {props.children} - - ); -} - -export function useCounter() { - return useContext(CounterContext); -} -``` - -```tsx tab title="Child.jsx" -// /context/counter-component.tsx -import { useCounter } from "./Context"; - -export function Child(props) { - const [count, { increment, decrement }] = useCounter(); - - return ( - <> -
    {count()}
    - - - - ); -} -``` - -This offers a way to manage state across your components without having to pass props through intermediate elements. - -## Debugging with context - -`createContext` takes in an _optional_ default value and it is possible it can return `undefined` if not provided. -When working with TypeScript, this can introduce type issues that make it difficult to determine why your component is not rendering as expected. - -To solve this issue, a default value can be specified when creating a context object, or errors can be handled manually through the use of a custom `useMyContext` utility: - -```tsx title="/context/counter-component.tsx" -import { useContext } from "solid-js"; - -function useMyContext() { - const value = useContext(MyContext); - - if (!value) { - throw new Error("Missing context Provider"); - } - - return value; -} - -function Child() { - const value = useMyContext(); - - return
    {value}
    ; -} -``` - -## Common issues with `createContext` and `useContext` - -If no default value is passed to `createContext`, it is possible for `useContext` to return `undefined`. - -:::note[More on default values] -Read more about default values in the [`createContext`](/reference/component-apis/create-context) entry. -::: - -Because of this, if an initial value was not passed to `createContext`, the TS type signature of `useContext` will indicate that -the value returned might be `undefined` (as mentioned above). -This can be quite annoying when you want to use the context inside a component, and particularly when immediately destructuring the context. -Additionally, if you use `useContext` and it returns `undefined` (which is often, but not always, the result of a bug), the error message thrown at runtime can be confusing. - -The most common solution for it is to wrap all uses of `useContext` in a function that will explicitly throw a helpful error if the context is `undefined`. -This also serves to narrow the type returned, so TS doesn't complain. -As an example: - -```ts title="/context/counter-component.tsx" -function useCounterContext() { - const context = useContext(CounterContext); - if (!context) { - throw new Error("can't find CounterContext"); - } - return context; -} -``` diff --git a/src/routes/(0)concepts/(5)stores.mdx b/src/routes/(0)concepts/(5)stores.mdx deleted file mode 100644 index 4c523e4db..000000000 --- a/src/routes/(0)concepts/(5)stores.mdx +++ /dev/null @@ -1,529 +0,0 @@ ---- -title: Stores -category: Concepts -order: 6 -use_cases: >- - complex state, nested objects, arrays, shared state, fine-grained updates, - state trees, global state -tags: - - stores - - state - - objects - - arrays - - nested - - produce - - reconcile -version: "1.0" -description: >- - Manage complex nested state efficiently with stores that provide fine-grained - reactivity for objects and arrays in Solid. ---- - -Stores are a state management primitive that provide a centralized way to handle shared data and reduce redundancy. -Unlike [signals](/concepts/signals), which track a single value and trigger a full re-render when updated, stores maintain fine-grained reactivity by updating only the properties that change. -They can produce a collection of reactive signals, each linked to an individual property, making them well-suited for managing complex state efficiently. - -## Creating a store - -Stores can manage many data types, including: objects, arrays, strings, and numbers. - -Using JavaScript's [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) mechanism, reactivity extends beyond just the top-level objects or arrays. -With stores, you can now target nested properties and elements within these structures to create a dynamic tree of reactive data. - -```jsx -import { createStore } from "solid-js/store"; - -// Initialize store -const [store, setStore] = createStore({ - userCount: 3, - users: [ - { - id: 0, - username: "felix909", - location: "England", - loggedIn: false, - }, - { - id: 1, - username: "tracy634", - location: "Canada", - loggedIn: true, - }, - { - id: 2, - username: "johny123", - location: "India", - loggedIn: true, - }, - ], -}); -``` - -### Top-level array stores - -While the examples above show a store as an object with properties, stores can also be arrays directly. -When creating a top-level array store, the setter syntax differs slightly since you target indices directly rather than navigating through property keys first. - -```jsx -import { createStore } from "solid-js/store"; - -// Store as a top-level array -const [users, setUsers] = createStore([ - { id: 0, username: "felix909", location: "England", loggedIn: false }, - { id: 1, username: "tracy634", location: "Canada", loggedIn: true }, - { id: 2, username: "johny123", location: "India", loggedIn: true }, -]); -``` - -To append a new item to a top-level array store, use the array's length as the index: - -```jsx -setUsers(users.length, { - id: 3, - username: "michael584", - location: "Nigeria", - loggedIn: false, -}); -``` - -To modify an existing item by index: - -```jsx -// Update username of the first user -setUsers(0, "username", "felix_updated"); - -// Update multiple properties at once -setUsers(1, { location: "USA", loggedIn: false }); -``` - -You can also use filtering functions to update items based on conditions: - -```jsx -// Log out all users from Canada -setUsers((user) => user.location === "Canada", "loggedIn", false); -``` - -## Accessing store values - -Store properties can be accessed directly from the state proxy through directly referencing the targeted property: - -```jsx -console.log(store.userCount); // Outputs: 3 -``` - -Accessing stores within a tracking scope follows a similar pattern to signals. -While signals are created using the [`createSignal`](/reference/basic-reactivity/create-signal) function and require calling the signal function to access their values, store values can be directly accessed without a function call. -This provides access to the store's value directly within a tracking scope: - -```jsx -const App = () => { - const [mySignal, setMySignal] = createSignal("This is a signal."); - const [store, setStore] = createStore({ - userCount: 3, - users: [ - { - id: 0, - username: "felix909", - location: "England", - loggedIn: false, - }, - { - id: 1, - username: "tracy634", - location: "Canada", - loggedIn: true, - }, - { - id: 2, - username: "johny123", - location: "India", - loggedIn: true, - }, - ], - }); - return ( -
    -

    Hello, {store.users[0].username}

    {/* Accessing a store value */} - {mySignal()} {/* Accessing a signal */} -
    - ); -}; -``` - -When a store is created, it starts with the initial state but does _not_ immediately set up signals to track changes. -These signals are created **lazily**, meaning they are only formed when accessed within a tracking scope. - -Once data is used within a tracking scope, such as within the return statement of a component function, computed property, or an effect, a signal is created and dependencies are established. - -For example, if you wanted to print out every new user, adding the console log below will not work because it is not within a tracked scope. - -```tsx ins={9} -const App = () => { - const [store, setStore] = createStore({ - userCount: 3, - users: [ ... ], - }) - - const addUser = () => { ... } - - console.log(store.users.at(-1)) // This won't work - - return ( -
    -

    Hello, {store.users[0].username}

    -

    User count: {store.userCount}

    - -
    - ) -} -``` - -Rather, this would need to be in a tracking scope, like inside a [`createEffect`](/reference/basic-reactivity/create-effect), so that a dependency is established. - -```tsx del={9} ins={10-12} -const App = () => { - const [store, setStore] = createStore({ - userCount: 3, - users: [ ... ], - }) - - const addUser = () => { ... } - - console.log(store.users.at(-1)) - createEffect(() => { - console.log(store.users.at(-1)) - }) - - return ( -
    -

    Hello, {store.users[0].username}

    -

    User count: {store.userCount}

    - -
    - ) -} -``` - -## Modifying store values - -Updating values within a store is best accomplished using a setter provided by the `createStore` initialization. -This setter allows for the modification of a specific key and its associated value, following the format `setStore(key, newValue)`: - -```jsx "setStore" -const [store, setStore] = createStore({ - userCount: 3, - users: [ ... ], -}) - -setStore("users", (currentUsers) => [ - ...currentUsers, - { - id: 3, - username: "michael584", - location: "Nigeria", - loggedIn: false, - }, -]) -``` - -The value of `userCount` could also be automatically updated whenever a new user is added to keep it synced with the users array: - -```tsx ins={11} -const App = () => { - const [store, setStore] = createStore({ - userCount: 3, - users: [ ... ], - }) - - const addUser = () => { ... } - - createEffect(() => { - console.log(store.users.at(-1)) - setStore("userCount", store.users.length) - }) - - return ( -
    -

    Hello, {store.users[0].username}

    -

    User count: {store.userCount}

    - -
    - ) -} -``` - -:::note -Separating the read and write capabilities of a store provides a valuable debugging advantage. - -This separation facilitates the tracking and control of the components that are accessing or changing the values. -::: -:::advanced -A little hidden feature of stores is that you can also create nested stores to help with setting nested properties. - -```jsx - const [store, setStore] = createStore({ - userCount: 3, - users: [ ... ], - }) - - const [users, setUsers] = createStore(store.users) - - setUsers((currentUsers) => [ - ...currentUsers, - { - id: 3, - username: "michael584", - location: "Nigeria", - loggedIn: false, - }, - ]) - -``` - -Changes made through `setUsers` will update the `store.users` property and reading `users` from this derived store will also be in sync with the values from `store.users`. - -Note that the above relies on `store.users` to be set already in the existing store. - -::: - -## Path syntax flexibility - -Modifying a store using this method is referred to as "path syntax." -In this approach, the initial arguments are used to specify the keys that lead to the target value you want to modify, while the last argument provides the new value. - -String keys are used to precisely target particular values with path syntax. -By specifying these exact key names, you can directly retrieve the targeted information. -However, path syntax goes beyond string keys and offers more versatility when accessing targeted values. - -Instead of employing the use of just string keys, there is the option of using an array of keys. -This method grants you the ability to select multiple properties within the store, facilitating access to nested structures. -Alternatively, you can use filtering functions to access keys based on dynamic conditions or specific rules. - - - -The flexibility in path syntax makes for efficient navigation, retrieval, and modification of data in your store, regardless of the store's complexity or the requirement for dynamic access scenarios within your application. - -## Modifying values in arrays - -Path syntax provides a convenient way to modify arrays, making it easier to access and update their elements. -Instead of relying on discovering individual indices, path syntax introduces several powerful techniques for array manipulation. - -### Appending new values - -To append values to an array in a store, use the setter function with the spread operator (`...`) or the path syntax. Both methods add an element to the array but differ in how they modify it and their reactivity behavior. - -The spread operator creates a new array by copying the existing elements and adding the new one, effectively replacing the entire `store.users` array. -This replacement triggers reactivity for all effects that depend on the array or its properties. - -```jsx -setStore("users", (otherUsers) => [ - ...otherUsers, - { - id: 3, - username: "michael584", - location: "Nigeria", - loggedIn: false, - }, -]); -``` - -The path syntax adds the new element by assigning it to the index equal to `store.users.length`, directly modifying the existing array. -This triggers reactivity only for effects that depend on the new index or properties like `store.users.length`, making updates more efficient and targeted. - -```jsx -setStore("users", store.users.length, { - id: 3, - username: "michael584", - location: "Nigeria", - loggedIn: false, -}); -``` - -### Modifying multiple elements - -With path syntax, you can target a subset of elements of an array, -or properties of an object, by specifying an array or range of indices. - -The most general form is to specify an array of values. -For example, if `store.users` is an array of objects, -you can set the `loggedIn` property of several indices at once like so: - -```jsx -setStore("users", [2, 7, 10], "loggedIn", false); -// equivalent to (but more efficient than): -setStore("users", 2, "loggedIn", false); -setStore("users", 7, "loggedIn", false); -setStore("users", 10, "loggedIn", false); -``` - -This array syntax also works for object property names. -For example, if `store.users` is an object mapping usernames to objects, -you can set the `loggedIn` property of several users at once like so: - -```jsx -setStore("users", ["me", "you"], "loggedIn", false); -// equivalent to (but more efficient than): -setStore("users", ["me"], "loggedIn", false); -setStore("users", ["you"], "loggedIn", false); -``` - -For arrays specifically, you can specify a range of indices via an object -with `from` and `to` keys (both of which are inclusive). -For example, assuming `store.users` is an array again, -you can set the `loggedIn` state for all users except index 0 as follows: - -```jsx -setStore("users", { from: 1, to: store.users.length - 1 }, "loggedIn", false); -// equivalent to (but more efficient than): -for (let i = 1; i <= store.users.length - 1; i++) { - setStore("users", i, "loggedIn", false); -} -``` - -You can also include a `by` key in a range object to specify a step size, -and thereby update a regular subset of elements. -For example, you can set the `loggedIn` state for even-indexed users like so: - -```jsx -setStore( - "users", - { from: 0, to: store.users.length - 1, by: 2 }, - "loggedIn", - false -); -// equivalent to (but more efficient than): -for (let i = 1; i <= store.users.length - 1; i += 2) { - setStore("users", i, "loggedIn", false); -} -``` - -Multi-setter syntax differs from the "equivalent" code in one key way: -a single store setter call automatically gets wrapped in a -[`batch`](/reference/reactive-utilities/batch), so all the elements update -at once before any downstream effects are triggered. - -### Dynamic value assignment - -Path syntax also provides a way to set values within an array using functions instead of static values. -These functions receive the old value as an argument, allowing you to compute the new value based on the existing one. -This dynamic approach is particularly useful for complex transformations. - -```jsx -setStore("users", 3, "loggedIn", (loggedIn) => !loggedIn); -``` - -### Filtering values - -To update elements in an array based on specific conditions, you can pass a function as an argument. -This function acts as a filter, receiving the old value and index, and gives you the flexibility to apply logic that targets specific cases. -This might include using methods like `.startsWith()`, `includes()`, or other comparison techniques to determine which elements should be updated. - -```jsx -// update users with username that starts with "t" -setStore("users", (user) => user.username.startsWith("t"), "loggedIn", false); - -// update users with location "Canada" -setStore("users", (user) => user.location == "Canada", "loggedIn", false); - -// update users with id 1, 2 or 3 -let ids = [1, 2, 3]; -setStore("users", (user) => ids.includes(user.id), "loggedIn", false); -``` - -## Modifying objects - -When using store setters to modify objects, if a new value is an object, it will be shallow merged with the existing value. -What this refers to is that the properties of the existing object will be combined with the properties of the "new" object you are setting, updating any overlapping properties with the values from the new object. - -What this means, is that you can directly make the change to the store _without_ spreading out properties of the existing user object. - -```jsx -setStore("users", 0, { - id: 109, -}); - -// is equivalent to - -setStore("users", 0, (user) => ({ - ...user, - id: 109, -})); -``` - -## Store utilities - -### Store updates with `produce` - -Rather than directly modifying a store with setters, Solid has the `produce` utility. -This utility provides a way to work with data as if it were a [mutable](https://developer.mozilla.org/en-US/docs/Glossary/Mutable) JavaScript object. -`produce` also provides a way to make changes to multiple properties at the same time which eliminates the need for multiple setter calls. - -```jsx -import { produce } from "solid-js/store"; - -// without produce -setStore("users", 0, "username", "newUsername"); -setStore("users", 0, "location", "newLocation"); - -// with produce -setStore( - "users", - 0, - produce((user) => { - user.username = "newUsername"; - user.location = "newLocation"; - }) -); -``` - -`produce` and `setStore` do have distinct functionalities. -While both can be used to modify the state, the key distinction lies in how they handle data. -`produce` allows you to work with a temporary draft of the state, apply the changes, then produce a new [immutable](https://developer.mozilla.org/en-US/docs/Glossary/Immutable) version of the store. -Comparatively, `setStore` provides a more straightforward way to update the store directly, without creating a new version. - -It's important to note, however, `produce` is specifically designed to work with **arrays** and **objects**. -Other collection types, such as JavaScript [Sets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) and [Maps](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), are not compatible with this utility. - -### Data integration with `reconcile` - -When new information needs to be merged into an existing store `reconcile` can be useful. -`reconcile` will determine the differences between new and existing data and initiate updates only when there are _changed_ values, thereby avoiding unnecessary updates. - -```jsx -import { createStore, reconcile } from "solid-js/store"; - -const [data, setData] = createStore({ - animals: ["cat", "dog", "bird", "gorilla"], -}); - -const newData = getNewData(); // eg. contains ['cat', 'dog', 'bird', 'gorilla', 'koala'] -setData("animals", reconcile(newData)); -``` - -In this example, the store will look for the differences between the existing and incoming data sets. -Consequently, only `'koala'` - the new edition - will cause an update. - -### Extracting raw data with `unwrap` - -When there is a need for dealing with data outside of a tracking scope, the `unwrap` utility offers a way to transform a store to a standard [object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object). -This conversion serves several important purposes. - -Firstly, it provides a snapshot of the current state without the processing overhead associated with reactivity. -This can be useful in situations where an unaltered, non-reactive view of the data is needed. -Additionally, `unwrap` provides a means to interface with third-party libraries or tools that anticipate regular JavaScript objects. -This utility acts as a bridge to facilitate smooth integrations with external components and simplifies the incorporation of stores into various applications and workflows. - -```jsx -import { createStore, unwrap } from "solid-js/store"; - -const [data, setData] = createStore({ - animals: ["cat", "dog", "bird", "gorilla"], -}); - -const rawData = unwrap(data); -``` - -To learn more about how to use Stores in practice, visit the [guide on complex state management](/guides/complex-state-management). diff --git a/src/routes/(0)concepts/(6)refs.mdx b/src/routes/(0)concepts/(6)refs.mdx deleted file mode 100644 index efaa7cde7..000000000 --- a/src/routes/(0)concepts/(6)refs.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: Refs -category: Concepts -use_cases: >- - dom access, element references, focus management, third-party libraries, - canvas manipulation, forwarding refs -tags: - - refs - - dom - - elements - - directives - - access - - forward -version: "1.0" -description: >- - Access and manipulate DOM elements directly using refs, forward refs between - components, and create custom directives. ---- - -Refs, or references, are a special attribute that can be attached to any element, and are used to reference a DOM element or a component instance. -They are particularly useful when you need to access the DOM nodes directly or invoke methods on a component. - -## Accessing DOM elements - -One way of accessing DOM elements is through [element selectors](https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors) such as [`document.querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector) or [`document.getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById). -Since elements in Solid can be added or removed from the DOM based on state, you need to wait until the element is attached to the DOM before accessing it. -This can be done by using [`onMount`](/reference/lifecycle/on-mount) to wait until the element is attached to the DOM before accessing it: - -Accessing DOM elements through element selectors is not recommended for this reason. -As elements with the same selectors are added and removed from the DOM, the first element that matches the selector will be returned, which may not be the element you want. - -## JSX as a value - -JSX can be used as a value and assigned to a variable when looking to directly access DOM elements. - -```tsx -function Component() { - const myElement =

    My Element

    ; - - return
    {myElement}
    ; -} -``` - -This lets you create and access DOM elements similar to [`document.createElement`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement) but without having to wait until it is attached to the DOM. -It can be used multiple times without having to worry about duplicate selectors. - -The downside of this approach is that it separates the element and any child elements from the rest of the JSX structure. -This makes the component's JSX structure more difficult to read and understand. - -## Refs in Solid - -Solid provides a ref system to access DOM elements directly inside the JSX template, which keeps the structure of the elements intact. - -To use [`ref`](/reference/jsx-attributes/ref), you declare a variable and use it as the `ref` attribute: - -```tsx {6} -function Component() { - let myElement; - - return ( -
    -

    My Element

    -
    - ); -} -``` - -These assignments occur at _creation time_ prior to the element being added to the DOM. -If access to an element is needed before it is added to the DOM, you can use the callback form of `ref`: - -```jsx -

    { - myElement = el; // el is created but not yet added to the DOM - }} -> - My Element -

    -``` - -:::note -In TypeScript, you must use a definitive assignment assertion. -Since Solid takes care of assigning the variable when the component is rendered, this signals to TypeScript that the variable will be assigned, even if it can't -confirm it. - -```tsx -let myElement!: HTMLDivElement; -``` - -::: - -### Signals as refs - -[Signals](/concepts/signals) can also be used as refs. -This is useful when you want to access the element directly, but the element may not exist when the component is first rendered, or may be removed from the DOM at some point. - -```jsx -function App() { - const [show, setShow] = createSignal(false) - let element!: HTMLParagraphElement - - return ( -
    - - - -

    This is the ref element

    -
    -
    - ) -} -``` - -In this example, the paragraph element is only rendered when the `show` signal is `true`. -When the component initializes, the paragraph element does not exist, so the `element` variable is not assigned. -Once the `show` signal is set to `true`, the paragraph element is rendered, and the `element` variable is assigned to the paragraph element. - -You can see a detailed view of the ref update lifecycle in this [Solid playground example](https://playground.solidjs.com/anonymous/22a1abfa-a0f5-44a6-bbe6-40387cf63b95). - -## Forwarding refs - -Forwarding refs is a technique that allows you to pass a ref from a parent component to a child component. -This is useful when you want to access the DOM element of a child component from the parent component. - -To forward a ref, you need to pass the ref to the child component, and then assign the ref to the child component's element. - -When a child component receives a `ref` attribute from its parent, the `ref` is passed as a callback function. -This is regardless of whether the parent passed it as a simple assignment or a callback. - -Once the child component receives the `ref`, it can be assigned to the element that the child component wants to expose through the `ref` attribute. -To access the `ref` in the child component, it is passed as a prop: - -```tsx -// Parent component -import { Canvas } from "./Canvas.jsx"; - -function ParentComponent() { - let canvasRef; - - const animateCanvas = () => { - // Manipulate the canvas using canvasRef... - }; - - return ( -
    - - -
    - ); -} - -// Child component -function Canvas(props) { - return ( -
    - {/* Assign the ref to the canvas element */} -
    - ); -} -``` - -In this example, the `canvas` element is directly assigned the `ref` attribute through the `props.ref` variable. -This forwards the reference to the parent component, giving it direct access to the `canvas` element. - -## Directives - -Directives allow the attachment of reusable behaviours to DOM elements. -The [`use:`](/reference/jsx-attributes/use) prefix is used to denote these custom directives. -Unlike props or attributes, directives operate at a lower level through providing fine-grained control over the elements they are attached to. - -Directives are like callback refs but they enable two extra features: - -- Having multiple directives on an element. -- Passing in reactive data to the callback. - -A directive is essentially a function with a specific signature: - -```typescript -function directive(element: Element, accessor: () => any): void; -``` - -- `element`: The DOM element that the directive is applied to. -- `accessor`: A function that gives access to the value(s) passed to the directive. - -The directive functions are called at render time, but are called before the element is added to the DOM. -Due to this order, elements are fully primed with their attributes, properties, or event listeners, therefore minimizing unexpected behaviors or premature interactions. - -Within directives, you're able to perform a variety of tasks, including: - -- creating [signals](/concepts/signals) -- initiating [effects](/guides/state-management#reacting-to-changes) -- adding [event listeners](/concepts/components/event-handlers) -- and more. - -To learn more about directives and how they work with TypeScript, refer to our [TypeScript for Solid guide](/configuration/typescript). diff --git a/src/routes/(0)index.mdx b/src/routes/(0)index.mdx index 6a35c72ec..bd0832d8a 100644 --- a/src/routes/(0)index.mdx +++ b/src/routes/(0)index.mdx @@ -11,74 +11,28 @@ tags: - getting-started - basics - framework -version: "1.0" +version: "2.0" description: >- - Solid is a reactive JavaScript framework for building fast, efficient UIs. - Learn about fine-grained reactivity and modern web development. + Documentation for Solid 2.0, the reactive JavaScript framework for building + user interfaces. --- -Solid is a modern JavaScript framework designed to build responsive and high-performing user interfaces (UI). -It prioritizes a simple and predictable development experience, making it a great choice for developers of all skill levels. +:::note[These docs are in beta] +Solid 2.0 and this documentation are in beta. +You may encounter missing pages and rough edges. +For Solid 1.x, SolidStart, and the current stable ecosystem, see the [Solid 1.x documentation](https://docs.solidjs.com/). +::: -## What is Solid? +Solid is a framework for building user interfaces on the web. +Solid 2.0 is a coordinated release of the whole platform: the core library, rendering, routing, head management, and the Vite plugin ship together and are designed to work together. -As a JavaScript framework, Solid embraces reactivity and fine-grained updates. +You can try Solid in the [playground](https://playground.solidjs.com/) or [start a project](/getting-started/quick-start) right away. -Reactivity, in programming, refers to an application's ability to respond to changes in data or user interactions. +## How these docs are organized -Traditionally, when a change occurs, the entire web page would need to reload to display the updated information. -In contrast, when using a fine-grained reactive system, updates are only applied to the parts of the page that need to be updated. - -Solid adopts the concept of fine-grained reactivity, updating only when the data the application depends on changes. -This decreases work and can result in faster load times and a smoother user experience overall. - -## Advantages of using Solid - -- **Performant**: Fine-grained reactivity allows Solid to update only what has changed, resulting in faster load times and smoother performance overall. - -- **Powerful**: Using less memory and processing power, Solid is capable of creating complex applications without compromising on functionality. - This also gives developers the flexibility over how and when updates happen. - -- **Pragmatic**: Rather than sticking to rigid structures or methods, Solid provides the freedom to choose the strategies and practices that work best for you. - -- **Productive**: Regardless of experience level, Solid's clear and predictable API makes developers' work simpler and more efficient. - -Solid aims to strike a balance between speed, efficiency, power, and flexibility, all while providing a developer-friendly environment. -This combination of features makes it a great choice to build responsive and high-performing UIs. - -## Quick links - -
    - - Learn the basics of Solid through this interactive tutorial. - - - Start your first project with a template that fits your needs. - - - Explore the Solid ecosystem and find useful tools and libraries. - - - Help improve Solid by contributing to the documentation. - -
    - -_Find our API documentation under the **Reference** tab_ - -Join the [Solid community on Discord](https://discord.com/invite/solidjs) to share your projects or get help from our community! +- [Getting started](/getting-started/quick-start): create a project and learn the project shapes. +- [Concepts](/concepts/reactivity): how Solid works — reactivity, components, and rendering. +- [Building apps](/building-apps/app-structure): the application layer — structure, server functions, sessions, environment, deployment. +- [Routing](/routing/overview): how routers plug in, with guides for Solid Router and TanStack Router. +- [Migration](/migration/from-solid-1): moving from Solid 1.x, SolidStart, and earlier ecosystem versions. +- Reference: API documentation for each package, organized by import specifier. diff --git a/src/routes/(1)advanced-concepts/(0)fine-grained-reactivity.mdx b/src/routes/(1)advanced-concepts/(0)fine-grained-reactivity.mdx deleted file mode 100644 index 2f222cebd..000000000 --- a/src/routes/(1)advanced-concepts/(0)fine-grained-reactivity.mdx +++ /dev/null @@ -1,305 +0,0 @@ ---- -title: Fine-grained reactivity -category: Advanced Concepts -use_cases: >- - optimizing performance, reducing re-renders, understanding solid fundamentals, - building efficient apps, custom reactive systems -tags: - - reactivity - - performance - - signals - - effects - - optimization - - fundamentals -version: "1.0" -description: >- - Master Solid's fine-grained reactivity system for targeted UI updates, optimal - performance, and efficient state management patterns. ---- - -Reactivity ensures automatic responses to data changes, eliminating the need for manual updates to the user interface (UI). -By connecting UI elements to the underlying data, updates become automated. -In a fine-grained reactive system an application will now have the ability to make highly _targeted and specific_ updates. - -An example of this can be seen in the contrast between Solid and [React](https://react.dev/). -In Solid, updates are made to the targeted attribute that needs to be changed, avoiding broader and, sometimes unnecessary, updates. -In contrast, React would re-execute an entire component for a change in the single attribute, which can be less efficient. - -Because of the fine-grained reactive system, unnecessary recalculations are avoided. -Through targeting only the areas of an application that have changed the user experience becomes smoother and more optimized. - -**Note:** If you're new to the concept of reactivity and want to learn the basics, consider starting with our [intro to reactivity guide](/concepts/intro-to-reactivity). - -## Reactive primitives - -In Solid's reactivity system, there are two key elements: signals and observers. -These core elements serve as the foundation for more specialized reactive features: - -- [Stores](/concepts/stores) which are [proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) that create, read, and write signals under the hood. -- [Memos](/concepts/derived-values/memos) resemble [effects](/concepts/effects) but are distinct in that they _return_ a signal and optimize computations through caching. - They update based on the behavior of effects, but are more ideal for computational optimization. -- [Resources](/guides/fetching-data), building on the concept of memos, convert the asynchronicity of network requests into synchronicity, where the results are embedded within a signal. -- Render effects are a tailored type of effect that initiate immediately, specifically designed for managing the rendering process. - -### Understanding signals - -[Signals](/concepts/signals) are like mutable variables that can point to a value now and another in the future. -They are made up of two primary functions: - -- **Getter**: how to read the current value of a signal. -- **Setter**: a way to modify or update a signal's value. - -In Solid, the [`createSignal`](/reference/basic-reactivity/create-signal) function can be used to create a signal. -This function returns the getter and setter as a pair in a two-element array, called a tuple. - -```js -import { createSignal } from "solid-js"; - -const [count, setCount] = createSignal(1); - -console.log(count()); // prints "1" - -setCount(0); // changes count to 0 - -console.log(count()); // prints "0" -``` - -Here, `count` serves as the getter, and `setCount` functions as the setter. - -### Effects - -[Effects](/concepts/effects) are functions that are triggered when the signals they depend on point to a different value. -They can be thought of as automated responders where any changes in the signal's value will trigger the effect to run. - -```jsx -import { createSignal, createEffect } from "solid-js"; - -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log(count()); -}); -``` - -The effect takes a function that is called whenever _any_ of the signals it relies on changes, such as `count` in this example. - -## Building a reactive system - -To grasp the concept of reactivity, it is often helpful to construct a reactive system from scratch. - -The following example will follow the observer pattern, where data entities (signals) will maintain a list of their subscribers (effects). -This is a way to notify subscribers whenever a signal they observe changes. - -Here is a basic code outline to begin: - -```jsx -function createSignal() {} - -function createEffect() {} - -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log("The count is " + count()); -}); -``` - -## Reactive primitives - -### `createSignal` - -The `createSignal` function performs two main tasks: - -1. Initialize the value (in this case, `count` is set to `0`). -2. Return an array with two elements: the getter and setter function. - -```tsx -function createSignal(initialValue) { - let value = initialValue; - - function getter() { - return value; - } - - function setter(newValue) { - value = newValue; - } - - return [getter, setter]; -} - -// .. -``` - -This allows you to retrieve the current value through the getter and make any changes via the setter. -At this stage, reactivity is not present, however. - -### `createEffect` - -`createEffect` defines a function that immediately calls the function that is passed into it: - -```jsx -// .. - -function createEffect(fn) { - fn(); -} - -// .. -``` - -### Making a system reactive - -Reactivity emerges when linking `createSignal` and `createEffect` and this happens through: - -1. Maintaining a reference to the current subscriber's function. -2. Registering this function during the creation of an effect. -3. Adding the function to a subscriber list when accessing a signal. -4. Notifying all subscribers when the signal has updated. - -```jsx -let currentSubscriber = null; - -function createSignal(initialValue) { - let value = initialValue; - const subscribers = new Set(); - - function getter() { - if (currentSubscriber) { - subscribers.add(currentSubscriber); - } - return value; - } - - function setter(newValue) { - if (value === newValue) return; // if the new value is not different, do not notify dependent effects and memos - value = newValue; - for (const subscriber of subscribers) { - subscriber(); // - } - } - - return [getter, setter]; -} - -// creating an effect -function createEffect(fn) { - const previousSubscriber = currentSubscriber; // Step 1 - currentSubscriber = fn; - fn(); - currentSubscriber = previousSubscriber; -} - -//.. -``` - -A variable is used to hold a reference to the current executing subscriber function. -This is used to determine which effects are dependent on which signals. - -Inside `createSignal`, the initial value is stored and a [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) is used to store any subscriber functions that are dependent on the signal. -This function will then return two functions for the signal: - -- The `getter` function checks to see if the current subscriber function is being accessed and, if it is, adds it to the list of subscribers before returning the _current_ value of the signal. -- The `setter` function evaluated the new value against the old value, notifying the dependent functions only when the signal has been updated. - -When creating the `createEffect` function, a reference to any previous subscribers is initialized to handle any possible nested effects present. -The current subscriber is then passed to the given function, which is run immediately. -During this run, if the effect accesses any signals it is then registered as a subscriber to those signals. -The current subscriber, once the given function has been run, will be reset to its previous value so that, if there are any nested effects, they are operated correctly. - -### Validating the reactive system - -To validate the system, increment the `count` value at one-second intervals: - -```jsx -//.. - -const [count, setCount] = createSignal(0); - -createEffect(() => { - console.log("The count is " + count()); -}); - -setInterval(() => { - setCount(count() + 1); -}, 1000); -``` - -This will display the incremented count value on the console at one-second intervals to confirm the reactive system's functionality. - -## Managing lifecycles in a reactive system - -In reactive systems, various elements, often referred to as "nodes", are interconnected. -These nodes can be signals, effects, or other reactive primitives. -They serve as the individual units that collectively make up the reactive behavior of the system. - -When a node changes, the system will re-evaluate the parts connected to that node. -This can result in updates, additions, or removals of these connections, which affect the overall behavior of the system. - -Now, consider a scenario where a condition influences the data used to calculate an output: - -```jsx -// Temperature.jsx -console.log("1. Initialize"); -const [temperature, setTemperature] = createSignal(72); -const [unit, setUnit] = createSignal("Fahrenheit"); -const [displayTemp, setDisplayTemp] = createSignal(true); - -const displayTemperature = createMemo(() => { - if (!displayTemp()) return "Temperature display is off"; - return `${temperature()} degrees ${unit()}`; -}); - -createEffect(() => console.log("Current temperature is", displayTemperature())); - -console.log("2. Turn off displayTemp"); -setDisplayTemp(false); - -console.log("3. Change unit"); -setUnit("Celsius"); - -console.log("4. Turn on displayTemp"); -setDisplayTemp(true); -``` - -In this example, the `createMemo` primitive is used to cache the state of a computation. -This means the computation doesn't have to be re-run if its dependencies remain unchanged. - -The `displayTemperature` memo has an early return condition based on the value of `displayTemp`. -When `displayTemp` is false, the memo returns a message saying "Temperature display is off," and as a result, `temperature` and `unit` are not tracked. - -If the `unit` is changed while `displayTemp` is false, however, the effect won't trigger since none of the memo's current dependencies (`displayTemp` in this case) have changed. - -### Synchronous nature of effect tracking - -The reactivity system described above operates synchronously. -This operation has implications for how effects and their dependencies are tracked. -Specifically, the system registers the subscriber, runs the effect function, and then unregisters the subscriber — all in a linear, synchronous sequence. - -Consider the following example: - -```jsx -createEffect(() => { - setTimeout(() => { - console.log(count()); - }, 1000); -}); -``` - -The `createEffect` function in this example, initiates a `setTimeout` to delay the console log. -Because the system is synchronous, it doesn't wait for this operation to complete. -By the time the `count` getter is triggered within the `setTimeout`, the global scope no longer has a registered subscriber. -As a result, this `count` signal will not add the callback as a subscriber which leads to potential issues with tracking the changes to `count`. - -### Handling asynchronous effects - -While the basic reactivity system is synchronous, frameworks like Solid offer more advanced features to handle asynchronous scenarios. -For example, the `on` function provides a way to manually specify the dependencies of an effect. -This is particularly useful for to make sure asynchronous operations are correctly tied into the reactive system. - -Solid also introduces the concept of resources for managing asynchronous operations. -Resources are specialized reactive primitives that convert the asynchronicity of operations like network requests into synchronicity, embedding the results within a signal. -The system can then track asynchronous operations and their state, keeping the UI up-to-date when the operation completes or its' state changes. - -Using resources in Solid can assist in complex scenarios when multiple asynchronous operations are involved and the completion may affect different parts of the reactive system. -By integrating resources into the system, you can ensure that dependencies are correctly tracked and that the UI remains consistent with the underlying asynchronous data. diff --git a/src/routes/(1)getting-started/(0)quick-start.mdx b/src/routes/(1)getting-started/(0)quick-start.mdx new file mode 100644 index 000000000..0b96fcbfb --- /dev/null +++ b/src/routes/(1)getting-started/(0)quick-start.mdx @@ -0,0 +1,38 @@ +--- +title: Quick start +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +Create a project from one of the Solid 2.0 templates: + +```bash +npx degit solidjs/templates/solid-v2/basic my-solid-project +cd my-solid-project +npm install # or pnpm install or yarn install +npm run dev +``` + +Open [http://localhost:3000](http://localhost:3000) to see your app. + +The `basic` template gives you a router with file-system routes, per-page titles, and a test suite, and builds to a purely static site. +There is no `index.html` and no mount file: the Vite plugin's start mode generates the entries around two files. + +- `src/App.tsx` is the app, router included. +- `src/Document.tsx` is the document shell. Site-wide head tags go here. + +Edit files under `src/routes` and the route table follows. + +## Other project shapes + +The templates come in three tiers, each a superset of the last. +Pick the one that matches what you are building, or read about [project shapes](/getting-started/project-shapes) to compare them. + +- `solid-v2/bare`: no router, pure static output. +- `solid-v2/basic`: router, file-system routes, testing. Still pure static. +- `solid-v2/fullstack`: streaming SSR with server functions, sessions, and API routes. + +## Getting help + +If you need assistance, ask in the [Discord chatroom](https://discord.com/invite/solidjs). diff --git a/src/routes/(1)getting-started/(1)project-shapes.mdx b/src/routes/(1)getting-started/(1)project-shapes.mdx new file mode 100644 index 000000000..c57219450 --- /dev/null +++ b/src/routes/(1)getting-started/(1)project-shapes.mdx @@ -0,0 +1,54 @@ +--- +title: Project shapes +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +Solid projects come in three shapes, reflected in the official templates. +Each tier is a strict superset of the last, and each comes with a deployment contract you can rely on. + +| Tier | Adds | Deployment contract | +| --- | --- | --- | +| `bare` | Solid, nothing else | `vite build` emits a purely static site | +| `basic` | Router, file-system routes, per-page titles, testing | Still purely static; deploy `dist/client` to any static host | +| `fullstack` | Streaming SSR, server functions, sessions, API routes | Static client assets plus a request handler in `dist/server` | + +Start with the smallest tier that does the job. +Moving up a tier later does not change the structure of your app: the same `src/App.tsx` and `src/Document.tsx` conventions carry through all three. + +## The `ssr` flip + +Every tier can switch between client rendering and server rendering with one boolean in `vite.config.ts`: + +```ts +import { defineConfig } from "vite"; +import solid from "vite-plugin-solid"; + +export default defineConfig({ + plugins: [ + solid({ + start: true, + ssr: true, // remove for a static shell rendered on the client + }), + ], +}); +``` + +Your app code carries over unchanged. +In client mode the document shell is prerendered as static HTML and pages render in the browser; with `ssr: true` pages stream from the server and hydrate. + +## Deploying `fullstack` + +The built server entry exports `handleRequest(request)`, an adapter-agnostic `Request -> Response` handler: + +```js +import { handleRequest } from "./dist/server/server.js"; + +// serve dist/client statically; everything else: +const response = await handleRequest(request); +``` + +The template's included `server.js` is the Node version of exactly that. +On web-native platforms (workers, Deno, `Bun.serve`) use `handleRequest` directly. +See [Deployment](/building-apps/deployment) for platform specifics. diff --git a/src/routes/(1)quick-start.mdx b/src/routes/(1)quick-start.mdx deleted file mode 100644 index c6c2854aa..000000000 --- a/src/routes/(1)quick-start.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Quick start -use_cases: >- - starting new project, project setup, first app, development environment, - templates -tags: - - quickstart - - setup - - templates - - getting-started - - playground -version: "1.0" -description: >- - Start building with Solid quickly. Try the playground, create projects with - templates, and get your first Solid app running in minutes. ---- - -## Try Solid online - -To experiment with Solid directly in your browser, head over to our [interactive playground](https://playground.solidjs.com/). -Prefer a full development setup? You can set up a complete environment using StackBlitz. -Start with the [TypeScript](https://stackblitz.com/github/solidjs/templates/tree/master/ts) or [JavaScript](https://stackblitz.com/github/solidjs/templates/tree/master/js) templates. - -## Create a Solid project - -:::note[Prerequisites] - -- Familiarity with the command line. -- A recent version of [Node.js](https://nodejs.org/en), [Bun](https://bun.sh/), or [Deno](https://deno.com/). - The latest LTS version is recommended. - -::: - -To create a new Solid application, navigate to the directory where you want to create your project and run the following command: - -```package-create -solid -``` - -This command installs and runs [create-solid](https://github.com/solidjs-community/solid-cli/tree/main/packages/create-solid), the official project scaffolding tool for Solid. -The CLI will guide you through a series of prompts, allowing you to choose options such as [starter templates](https://github.com/solidjs/templates), TypeScript support, and whether to include [Solid's full-stack framework, SolidStart](/solid-start/v2): - -```shell -◆ Project Name -| - -◆ Is this a SolidStart project? -| ● Yes / ○ No - -◆ Which template would you like to use? -│ ● ts -│ ○ ts-vitest -│ ○ ts-uvu -│ ○ ts-unocss -│ ○ ts-tailwindcss - -◆ Use TypeScript? -│ ● Yes / ○ No -``` - -Once the project is created, follow the instructions to install the dependencies and start the development server: - -```sh title="npm" tab="package-manager" -│ cd solid-project -│ npm install -│ npm run dev -``` - -```sh title="pnpm" tab="package-manager" -│ cd solid-project -│ pnpm install -│ pnpm dev -``` - -```sh title="yarn" tab="package-manager" -│ cd solid-project -│ yarn install -│ yarn dev -``` - -```sh title="bun" tab="package-manager" -│ cd solid-project -│ bun install -│ bun run dev -``` - -```sh title="deno" tab="package-manager" -│ cd solid-project -│ deno install -│ deno run dev -``` - -You should now have your Solid project running! diff --git a/src/routes/(2)concepts/(0)reactivity.mdx b/src/routes/(2)concepts/(0)reactivity.mdx new file mode 100644 index 000000000..9731aa69b --- /dev/null +++ b/src/routes/(2)concepts/(0)reactivity.mdx @@ -0,0 +1,11 @@ +--- +title: "Reactivity" +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +:::note[Planned] +This page has not been written yet. +It will cover signals, memos, and effects: how Solid tracks reads and schedules updates. +::: diff --git a/src/routes/(2)concepts/(1)async-reactivity.mdx b/src/routes/(2)concepts/(1)async-reactivity.mdx new file mode 100644 index 000000000..f0dfe9567 --- /dev/null +++ b/src/routes/(2)concepts/(1)async-reactivity.mdx @@ -0,0 +1,11 @@ +--- +title: "Async reactivity" +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +:::note[Planned] +This page has not been written yet. +It will cover async values as first-class reactive state: `isPending`, `latest`, `flush`, `onSettled`, actions, and `refresh`. +::: diff --git a/src/routes/(2)concepts/(2)stores.mdx b/src/routes/(2)concepts/(2)stores.mdx new file mode 100644 index 000000000..f8dcce053 --- /dev/null +++ b/src/routes/(2)concepts/(2)stores.mdx @@ -0,0 +1,11 @@ +--- +title: "Stores" +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +:::note[Planned] +This page has not been written yet. +It will cover `createStore`, projections, and optimistic updates for nested reactive state. +::: diff --git a/src/routes/(2)concepts/(3)components-and-jsx.mdx b/src/routes/(2)concepts/(3)components-and-jsx.mdx new file mode 100644 index 000000000..177e9f470 --- /dev/null +++ b/src/routes/(2)concepts/(3)components-and-jsx.mdx @@ -0,0 +1,11 @@ +--- +title: "Components and JSX" +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +:::note[Planned] +This page has not been written yet. +It will cover components, props, control flow (`For`, `Repeat`, `Show`, `Switch`), context, and `children`. +::: diff --git a/src/routes/(2)concepts/(4)boundaries.mdx b/src/routes/(2)concepts/(4)boundaries.mdx new file mode 100644 index 000000000..3bfdbf0af --- /dev/null +++ b/src/routes/(2)concepts/(4)boundaries.mdx @@ -0,0 +1,11 @@ +--- +title: "Boundaries" +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +:::note[Planned] +This page has not been written yet. +It will cover `Loading`, `Errored`, and `Reveal`, and their primitive forms. +::: diff --git a/src/routes/(2)concepts/(5)rendering-and-ssr.mdx b/src/routes/(2)concepts/(5)rendering-and-ssr.mdx new file mode 100644 index 000000000..c6b589963 --- /dev/null +++ b/src/routes/(2)concepts/(5)rendering-and-ssr.mdx @@ -0,0 +1,11 @@ +--- +title: "Rendering and SSR" +titleTemplate: ":title" +mainNavExclude: true +version: "2.0" +--- + +:::note[Planned] +This page has not been written yet. +It will cover the rendering model: `render`, `hydrate`, streaming SSR, and hydration control. +::: diff --git a/src/routes/(2)guides/(0)styling-components/css-modules.mdx b/src/routes/(2)guides/(0)styling-components/css-modules.mdx deleted file mode 100644 index 049ae3d48..000000000 --- a/src/routes/(2)guides/(0)styling-components/css-modules.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: CSS modules -category: Guides / Styling Components -order: 3 -mainNavExclude: true -use_cases: >- - component styling, scoped styles, style encapsulation, preventing css - conflicts, modular css -tags: - - styling - - css - - modules - - scoped - - components - - encapsulation -version: "1.0" -description: >- - Use CSS Modules in Solid for locally scoped styles, preventing global - conflicts and ensuring component style encapsulation. ---- - -CSS Modules are CSS files where class names, animations, and media queries are scoped locally by default. -These provide a way to encapsulate styles within components, preventing global conflicts and optimizing the final output by bundling only the used selectors. - -## Creating CSS module files - -Begin by creating a CSS module file. -Conventionally, these files have a `.module.css` extension, like `style.module.css`. -However, you can also use other extensions, such as `.scss` and `.sass`. - -```css -/* styles.module.css */ -.foo { - color: red; -} -.bar { - background-color: blue; -} -``` - -**Note:** Avoid the use of HTML tags in CSS modules. -Since they are not considered pure selectors, it can lead to specificity issues which can make it more difficult to override with other styles and lead to unexpected behaviors. - -## Using modules in components - -1. **Importing styles:** In your component file (eg. `Component.jsx`), import the styles from the CSS module. - -```jsx -// component.jsx -import styles from "styles.module.css"; -``` - -2. **Applying styles:** Use the imported styles by referencing them as properties of the styles object in your JSX: - -```jsx -function Component() { - return ( - <> -
    Hello, world!
    - - ); -} -``` - -3. **Using a single style:** If you only need one style from the module, import and apply it directly: - -```jsx -// component.jsx -import styles from "styles.module.css"; - -function Component() { - return ( - <> -
    Hello, world!
    - - ); -} -``` - -4. **Mixing with regular class names:** You can combine CSS module syntax with regular string class names, as well: - -```jsx -// component.jsx -import styles from "styles.module.css"; - -function Component() { - return ( - <> -
    Hello, world!
    - - ); -} -``` - -**Note:** If your styles have dashes in their names, use bracket notation: - -```jsx -const className = styles["foo-with-dash"]; -``` diff --git a/src/routes/(2)guides/(0)styling-components/less.mdx b/src/routes/(2)guides/(0)styling-components/less.mdx deleted file mode 100644 index 5923bba97..000000000 --- a/src/routes/(2)guides/(0)styling-components/less.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: LESS -category: Guides / Styling Components -order: 2 -mainNavExclude: true -use_cases: >- - css preprocessing, style variables, mixins, nested styles, programmatic - styling -tags: - - styling - - less - - preprocessor - - variables - - mixins - - css -version: "1.0" -description: >- - Integrate LESS preprocessor in Solid apps for variables, mixins, and - programmatic CSS features to write cleaner stylesheets. ---- - -[LESS](https://lesscss.org/) is a preprocessor based on JavaScript. -It provides the ability to use mixins, variables, and other programmatic tools, making styling code cleaner and less redundant. - -## Installation - -To utilize LESS in a Solid app, it will need to be installed as a development dependency: - -```package-install-dev -less -``` - -## Using LESS in your app - -Start by creating a `.less` file in the `src` directory: - -```less -//styles.less -.foo { - color: red; -} -.bar { - background-color: blue; -} -``` - -The basic syntax of LESS is very similar to CSS. -However, LESS allows the declaration and usage of variables: - -```less -//styles.less -@plainred: red; -@plainblue: blue; -.foo { - color: @plainred; -} -.bar { - background-color: @plainblue; -} -``` - -To use these styles in a Solid component, import the `.less` file: - -```jsx -//component.jsx -import "./styles.less"; - -function Component() { - return ( - <> -
    Hello, world!
    - - ); -} -``` - -By changing the file extension of the imported styles to `.less`, Vite will recognize it as a LESS file and compile it to CSS on demand. diff --git a/src/routes/(2)guides/(0)styling-components/macaron.mdx b/src/routes/(2)guides/(0)styling-components/macaron.mdx deleted file mode 100644 index 8ff9f1799..000000000 --- a/src/routes/(2)guides/(0)styling-components/macaron.mdx +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: Macaron -category: Guides / Styling Components -order: 4 -mainNavExclude: true -use_cases: >- - css-in-js styling, type-safe styles, styled components, variant-based styling, - compile-time css -tags: - - styling - - css-in-js - - macaron - - styled-components - - typescript - - variants -version: "1.0" -description: >- - Style Solid components with Macaron's compile-time CSS-in-JS, offering - type-safe styled components and variant-based styling. ---- - -[Macaron](https://macaron.js.org/) is compile-time CSS-in-JS library that offers type safety. - -## Installation - -1. Install and set up the macaron plugin for your bundler: - -```package-install -@macaron-css/core @macaron-css/solid -``` - -2. Within your `vite.config.js` folder, add the macaron plugin prior to other plugins: - -```js -import { macaronVitePlugin } from "@macaron-css/vite"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [ - macaronVitePlugin(), - // other plugins - ], -}); -``` - -## Usage - -1. Import `styled` from `@macaron-css/solid` and create a styled component: - -```jsx -// button.tsx -import { styled } from "@macaron-css/solid"; - -const Button = styled("button", {}); -``` - -2. Add styles that will be applied to the components by default: - -```jsx -import { styled } from "@macaron-css/solid"; - -const Button = styled("button", { - base: { - backgroundColor: "red", - borderRadius: "10px", - }, -}); -``` - -Variants can be added using the `variants` key: - -```jsx -import { styled } from "@macaron-css/solid"; - -const Button = styled("button", { - base: { - backgroundColor: "red", - borderRadius: "10px", - }, - variants: { - color: { - violet: { - backgroundColor: "violet", - }, - gray: { - backgroundColor: "gray", - }, - }, - }, -}); -``` - -Additionally, the `defaultVariants` feature is set to `variants` by default. This can be overridden at the time of usage: - -```jsx -import { styled } from "@macaron-css/solid"; - -const Button = styled("button", { - base: { - backgroundColor: "red", - borderRadius: "10px", - }, - variants: { - color: { - violet: { - backgroundColor: "violet", - }, - gray: { - backgroundColor: "gray", - }, - }, - }, - defaultVariants: { - color: "blue", - }, -}); -``` - -These components can be used like any other Solid component, with type-safe props derived from your variants. -For more information on how to use macaron, visit their [documentation](https://macaron.js.org/docs/installation/). diff --git a/src/routes/(2)guides/(0)styling-components/sass.mdx b/src/routes/(2)guides/(0)styling-components/sass.mdx deleted file mode 100644 index 7f5f6bb3b..000000000 --- a/src/routes/(2)guides/(0)styling-components/sass.mdx +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: SASS -category: Guides / Styling Components -order: 1 -mainNavExclude: true -use_cases: >- - css preprocessing, nested styles, style variables, mixins, scss syntax, - modular styling -tags: - - styling - - sass - - scss - - preprocessor - - variables - - css - - mixins -version: "1.0" -description: >- - Configure SASS/SCSS in Solid projects for advanced CSS preprocessing with - variables, nesting, mixins, and modular stylesheets. ---- - -[SASS](https://sass-lang.com/) is a popular CSS preprocessor that makes authoring CSS easier. -It is a superset of CSS and offers two syntaxes: SCSS and the indented syntax (often referred to as just "SASS"). - -## Installation - -Depending on your package manager, SASS can be installed as a development dependency: - -```package-install-dev -sass -``` - -## Convert filename extensions - -After installation, the `.css` filename extensions will have to be changed to `.scss` or `.sass`. -The `.scss` syntax is a strict superset of CSS, while `.sass` offers a more relaxed syntax. -Vite, which is integrated with Solid, supports both. -However, `.scss` is generally recommended. - -```scss -// Card.scss -.grid { - display: grid; - &-center { - place-items: center; - } -} -.screen { - min-height: 100vh; -} -.card { - height: 160px; - aspect-ratio: 2; - border-radius: 16px; - background-color: white; - box-shadow: 0 0 0 4px hsl(0 0% 0% / 15%); -} -``` - -In a Solid component: - -```jsx -// Card.jsx -import "./card.scss"; - -function Card() { - return ( - <> -
    -
    Hello, world!
    -
    - - ); -} -``` - -By simply changing the file extension from `.css` to `.scss` or `.sass` , Vite will automatically recognize these files and compile SASS to CSS on demand. -When building in production, all SASS files are converted to CSS. -This ensures compatibility with most modern browsers. diff --git a/src/routes/(2)guides/(0)styling-components/tailwind-v3.mdx b/src/routes/(2)guides/(0)styling-components/tailwind-v3.mdx deleted file mode 100644 index f168abc83..000000000 --- a/src/routes/(2)guides/(0)styling-components/tailwind-v3.mdx +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Tailwind CSS v3 -category: Guides / Styling Components -order: 7 -mainNavExclude: true -use_cases: >- - utility-first css, rapid prototyping, responsive design, consistent styling, - atomic css classes -tags: - - styling - - tailwind - - utility-css - - responsive - - postcss - - atomic-css -version: "1.0" -description: >- - Set up Tailwind CSS v3 in Solid apps for utility-first styling, rapid - development, and consistent responsive design patterns. ---- - -[Tailwind CSS v3](https://v3.tailwindcss.com/) is an on-demand utility CSS library that integrates seamlessly with Solid as a built-in PostCSS plugin. - -## Installation - -1. Install Tailwind CSS as a development dependency: - -```package-install-dev -tailwindcss@3 postcss autoprefixer -``` - -2. Next, run the init command to generate both `tailwind.config.js` and `postcss.config.js`. - -```package-exec -tailwindcss init -p -``` - -3. Since Tailwind CSS is configuration-driven, after initializing, a `tailwind.config.js` file will be created at the root of your project directory: - -```js -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], - theme: { - extend: {}, - }, - plugins: [], -}; -``` - -For a deeper dive into configuration, you can check out the [Tailwind Official Documentation](https://tailwindcss.com/docs/configuration). - -## Add Tailwind directives - -In your `src/index.css` file, add the following Tailwind directives: - -```css -@tailwind base; -@tailwind components; -@tailwind utilities; -``` - -These directives inform PostCSS that you're using Tailwind and establish the order of the directives. You can append custom CSS below these directives. - -## Import Tailwind CSS - -Import your `index.css` file into the root `index.jsx` or `index.tsx` file: - -```jsx -import { render } from "solid-js/web" -import App from "./App" -import "./index.css" - -render(() => , document.getElementById('root') as HTMLElement); -``` - -## Usage - -With Tailwind CSS set up, you can now utilize its utility classes. -For instance, if you previously had a `Card.css` file, you can replace or remove it: - -``` -/* src/components/Card.css */ -/* Remove or replace these styles with Tailwind utility classes */ -``` - -Update your components to use Tailwind's utility classes: - -```jsx -/* src/components/Card.jsx */ -function Card() { - return ( -
    -
    - Hello, world! -
    -
    - ); -} -``` - -## Support - -For additional assistance, refer to the [Tailwind CSS/Vite integration guide](https://tailwindcss.com/docs/guides/vite). diff --git a/src/routes/(2)guides/(0)styling-components/tailwind.mdx b/src/routes/(2)guides/(0)styling-components/tailwind.mdx deleted file mode 100644 index 96cc9e792..000000000 --- a/src/routes/(2)guides/(0)styling-components/tailwind.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Tailwind CSS -category: Guides / Styling Components -order: 5 -mainNavExclude: true -use_cases: >- - styling components, utility classes, rapid ui development, responsive design, - production builds -tags: - - styling - - css - - tailwind - - postcss - - utilities - - design -version: "1.0" -description: >- - Set up Tailwind CSS v4 in your Solid app for utility-first styling. Configure - PostCSS, import styles, and build responsive UIs efficiently. ---- - -:::note -This guide is for Tailwind CSS v4. For **Tailwind CSS v3** refer to [Tailwind CSS v3](/guides/styling-components/tailwind-v3). -::: - -[Tailwind CSS](https://tailwindcss.com/) is an on-demand utility CSS library that integrates seamlessly with Solid as a built-in PostCSS plugin. - -## Installation - -1. Install Tailwind CSS as a development dependency: - -```package-install-dev -tailwindcss @tailwindcss/postcss postcss -``` - -2. Add `@tailwind/postcss` to the `plugins` in your PostCSS configuration. If you do not have a PostCSS configuration file, create a new one called `postcss.config.mjs`. - -```js title="postcss.config.mjs" -export default { - plugins: { - "@tailwindcss/postcss": {}, - }, -}; -``` - -For a deeper dive into configuration, you can check out the [Tailwind Official Documentation](https://tailwindcss.com/docs/configuration). - -## Import Tailwind CSS - -Add an `@import` to your `src/index.css` file that imports Tailwind CSS. - -```css title="src/index.css" -@import "tailwindcss"; -``` - -## Import your CSS file - -Import your `index.css` file into the root `index.jsx` or `index.tsx` file: - -```jsx -import { render } from "solid-js/web" -import App from "./App" -import "./index.css" - -render(() => , document.getElementById('root') as HTMLElement); -``` - -## Usage - -With Tailwind CSS set up, you can now utilize its utility classes. -For instance, if you previously had a `Card.css` file, you can replace or remove it: - -``` -/* src/components/Card.css */ -/* Remove or replace these styles with Tailwind utility classes */ -``` - -Update your components to use Tailwind's utility classes: - -```jsx -/* src/components/Card.jsx */ -function Card() { - return ( -
    -
    - Hello, world! -
    -
    - ); -} -``` - -## Support - -For additional assistance, refer to the [Tailwind CSS/Vite integration guide](https://tailwindcss.com/docs/guides/vite). diff --git a/src/routes/(2)guides/(0)styling-components/uno.mdx b/src/routes/(2)guides/(0)styling-components/uno.mdx deleted file mode 100644 index 0138a885b..000000000 --- a/src/routes/(2)guides/(0)styling-components/uno.mdx +++ /dev/null @@ -1,98 +0,0 @@ ---- -title: UnoCSS -category: Guides / Styling Components -order: 6 -mainNavExclude: true -use_cases: >- - styling components, utility css, on-demand styles, vite integration, atomic - css -tags: - - styling - - css - - unocss - - vite - - utilities -version: "1.0" -description: >- - Integrate UnoCSS with Solid for on-demand utility CSS. Configure Vite plugin, - import styles, and create efficient atomic CSS designs quickly. ---- - -[UnoCSS](https://unocss.dev/) is an on-demand utility CSS library that integrates seamlessly with Solid as a Vite plugin. - -## Install Vite plugin - -To get started with UnoCSS in your Solid app: - -```package-install-dev -unocss -``` - -## Import Vite plugin - -After installation, open your `vite.config.js` or `vite.config.ts`. The default Solid Vite configuration looks like this: - -```jsx -import { defineConfig } from "vite"; -import solidPlugin from "vite-plugin-solid"; - -export default defineConfig({ - plugins: [solidPlugin()], - server: { - port: 3000, - }, - build: { - target: "esnext", - }, -}); -``` - -Now, import `unocssPlugin` from "unocss/vite" and add it to the plugins array: - -```jsx -import { defineConfig } from "vite"; -import unocssPlugin from "unocss/vite"; -import solidPlugin from "vite-plugin-solid"; - -export default defineConfig({ - plugins: [unocssPlugin(), solidPlugin()], - server: { - port: 3000, - }, - build: { - target: "esnext", - }, -}); -``` - -Ensure that `unocssPlugin` is ordered before `solidPlugin` to prevent certain edge cases. - -## Import UnoCSS - -In your root `index.jsx` or `index.tsx` file, import UnoCSS: - -```jsx -/* @refresh reload */ -import "uno.css" -import { render } from "solid-js/web" -import "./index.css" -import App from "./App" - -render(() => , document.getElementById('root') as HTMLElement); -``` - -Alternatively, you can use the alias `import "virtual:uno.css"`: - -```jsx -/* @refresh reload */ -import "virtual:uno.css" -import { render } from "solid-js/web" -import "./index.css" -import App from "./App" - -render(() => , document.getElementById('root') as HTMLElement); -``` - -#### Support - -For additional assistance, refer to the [UnoCSS/Vite integration guide](https://unocss.dev/integrations/vite) . diff --git a/src/routes/(2)guides/(0)styling-your-components.mdx b/src/routes/(2)guides/(0)styling-your-components.mdx deleted file mode 100644 index 4ab55ba03..000000000 --- a/src/routes/(2)guides/(0)styling-your-components.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Styling your components -category: Guides -order: 1 -use_cases: >- - styling components, choosing css solutions, css frameworks, preprocessors, - css-in-js -tags: - - styling - - css - - preprocessors - - css-in-js - - frameworks -version: "1.0" -description: >- - Explore Solid's flexible styling options: CSS preprocessors, CSS Modules, - CSS-in-JS, and utility frameworks for component styling needs. ---- - -Solid provides flexible and versatile ways to style your components. -[`class` and `style` bindings](/concepts/components/class-style) can both be added to dynamically style components with plain CSS. -Solid also supports a range of styling methods - from traditional CSS preprocessors to modern CSS-in-JS solutions - ensuring the flexibility to choose the best approach for your projects. - -## CSS preprocessors - -
    - - - - -
    - -SASS -LESS - -## CSS modules - - - -## CSS-in-JS - -CSS-in-JS is a modern approach to styling components. -Within the [Solid ecosystem](https://www.solidjs.com/ecosystem), there are various libraries and solutions available for working with CSS-in-JS, including but not limited to: - -- [Solid Styled Components](https://github.com/solidjs/solid-styled-components) -- [Solid Styled JSX](https://github.com/solidjs/solid-styled-jsx) - -CSS-in-JS libraries often come with their own set of APIs and methods for defining, updating, and applying styles dynamically. -Many also offer features like theming, media queries, and server-side rendering support right out of the box. - -**Note:** Before choosing a CSS-in-JS library, it is recommended to check its compatibility with Solid. - -### Macaron - - -## CSS frameworks - -CSS frameworks provide pre-styled components and utility classes to speed up development. - -
    - - - - -
    diff --git a/src/routes/(2)guides/(1)deployment-options/aws-via-flightcontrol.mdx b/src/routes/(2)guides/(1)deployment-options/aws-via-flightcontrol.mdx deleted file mode 100644 index 208b56024..000000000 --- a/src/routes/(2)guides/(1)deployment-options/aws-via-flightcontrol.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: AWS via Flightcontrol -category: Guides / Deployment -order: 1 -mainNavExclude: true -use_cases: >- - aws deployment, automated deployments, continuous integration, github - integration, cloud hosting -tags: - - aws - - deployment - - flightcontrol - - automation - - github - - hosting -version: "1.0" -description: >- - Deploy Solid apps to AWS with Flightcontrol's automated platform featuring - GitHub integration and continuous deployment. ---- - -[Flightcontrol](https://www.flightcontrol.dev/) is a platform that fully automates deployments to Amazon Web Services (AWS). -For more information on Flightcontrol's capabilities, you can [visit their docs](https://www.flightcontrol.dev/docs). - -## Connecting to a git repository - -Flightcontrol offers a GitHub integration, leveraging its continuous development actions. - -To get started with Flightcontrol's GitHub integration, you'll first need to log in or sign up to the Flightcontrol platform. -After you're logged in, simply link your GitHub account to Flightcontrol. - -Once connected, Flightcontrol will take care of the rest. -It automatically detects any new pushes to your specified GitHub branches and builds your project. -The build process uses the commands in your `package.json` file and adheres to the settings that you have configured in Flightcontrol. -No additional setup is needed. - - - -## Using the dashboard - -1. In the Flightcontrol dashboard, create a new project and select the repository you wish to use as the source. - -2. Choose the GUI as your configuration type. - -3. Add your Solid site as a static site by clicking the "Add a Static Site" option. - - - -5. Label your output directory as `dist`. - -6. If your project requires environment variables, add them in the designated area: - - - -7. Finally, connect your AWS account to complete the setup. - - - -## Using code - -1. Navigate to your Flightcontrol dashboard and initiate a new project. - Choose the repository you'd like to use as the source. - -2. Opt for the `flightcontrol.json` as your configuration type. - - - -3. Add a new file named `flightcontrol.json` at the root of your selected repository. - Below is an example configuration: - -```json frame="terminal" -{ - "$schema": "https://app.flightcontrol.dev/schema.json", - "environments": [ - { - "id": "production", - "name": "Production", - "region": "us-west-2", - "source": { - "branch": "main" - }, - "services": [ - { - "id": "my-static-solid", - "buildType": "nixpacks", - "name": "My static solid site", - "type": "static", - "domain": "solid.yourapp.com", - "outputDirectory": "dist", - "singlePageApp": true - } - ] - } - ] -} -``` diff --git a/src/routes/(2)guides/(1)deployment-options/aws-via-sst.mdx b/src/routes/(2)guides/(1)deployment-options/aws-via-sst.mdx deleted file mode 100644 index 52ad58fe2..000000000 --- a/src/routes/(2)guides/(1)deployment-options/aws-via-sst.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: AWS via SST (SolidStart v1) -category: Guides / Deployment -order: 1 -mainNavExclude: true -use_cases: >- - serverless deployment, aws lambda, container deployment, cloud infrastructure, - production deployment -tags: - - aws - - sst - - serverless - - lambda - - deployment - - containers -version: "1.0" -description: >- - Deploy SolidStart v1 apps to AWS Lambda or containers using SST framework - with streamlined configuration and deployment. ---- - -[SST](https://sst.dev/) is a framework for deploying applications to any cloud provider. It has a built-in way to deploy SolidStart apps to AWS Lambda. For additional details, you can [visit their docs](https://sst.dev/docs/). - -:::caution[SolidStart v1 only] -SST's built-in `sst.aws.SolidStart` component currently expects `app.config.ts` and the Vinxi output used by SolidStart v1. It is not compatible with SolidStart v2's Vite-based build. For a SolidStart v2 app, see [Deployment plugins](/solid-start/v2/guides/deployment-plugins). -::: - -## Quick start - -1. [Create a SolidStart app](/solid-start/v1/getting-started). - -2. In your project, init SST. - -```package-exec -sst@latest init -``` - -3. This will detect your SolidStart app and ask you to update your `app.config.ts`. - -```ts title="app.config.ts" -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - preset: "aws-lambda", - awsLambda: { - streaming: true, - }, - }, -}); -``` - -4. When you are ready, you can deploy your app using: - -```package-exec -sst@latest deploy --stage production -``` - -You can [read the full tutorial on the SST docs](https://sst.dev/docs/start/aws/solid). - -## Deploy to a Container - -You can also deploy your SolidStart app to a [container](https://sst.dev/docs/start/aws/solid#containers) using SST. diff --git a/src/routes/(2)guides/(1)deployment-options/cloudflare.mdx b/src/routes/(2)guides/(1)deployment-options/cloudflare.mdx deleted file mode 100644 index 6a1b5833a..000000000 --- a/src/routes/(2)guides/(1)deployment-options/cloudflare.mdx +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Cloudflare -category: Guides / Deployment -order: 2 -mainNavExclude: true -use_cases: >- - static site hosting, jamstack deployment, edge deployment, cdn hosting, web - publishing -tags: - - cloudflare - - pages - - deployment - - wrangler - - hosting - - jamstack -version: "1.0" -description: >- - Deploy Solid apps to Cloudflare Pages for fast, global edge hosting with - built-in CDN and simple Git integration setup. ---- - -[Cloudflare Pages](https://pages.cloudflare.com/) is a JAMstack platform for frontend developers, where JAMstack stands for JavaScript, APIs, and Markup. -For additional details and features, you can [visit the Cloudflare website](https://pages.cloudflare.com/). - -## Using the Cloudflare's web interface - -1. Navigate to the [Cloudflare login page](https://dash.cloudflare.com/login) and log in or sign up. - - - -2. After logging in, find "Pages" in the left-hand navigation bar. - Add a new project by clicking "Create a project," then choose "Connect to Git." - - - -3. You'll have the option to install Cloudflare Pages on all your repositories or select ones. - Choose the repository that contains your Solid project. - - - -4. Configure your build settings: - -- The project name will default to the repository name, but you can change it if you wish. -- In the "build command" field, enter `npm run build` . -- For the "build output directory" field, use `dist` . -- Add an environment variable `NODE_VERSION` and set its value to the version of Node.js you're using. - -**Note:** This step is crucial because Cloudflare Pages uses a version of Node.js older than v13, which may not fully support Vite, the bundler used in Solid projects. - - - -5. Once you've configured the settings, click "Save and Deploy." - In a few minutes, your Solid project will be live on Cloudflare Pages, accessible via a URL formatted as `project_name.pages.dev`. - -## Using the Wrangler CLI - -Wrangler is a command-line tool for building Cloudflare Workers. -Here are the steps to deploy your Solid project using Wrangler. - -1. Use your package manager of choice to install the Wrangler command-line tool: - -```package-install-global -wrangler -``` - -2. Open your terminal and run the following command to log in: - -```bash frame="none" -wrangler login -``` - -3. Build your project using the following command: - -```package-run -build -``` - -4. Deploy using Wrangler: - -```bash -wrangler pages deploy dist -``` - -After running these commands, your project should be live. -While the terminal may provide a link, it's more reliable to check your Cloudflare Pages dashboard for the deployed URL, which usually follows the format `project-name.pages.dev`. diff --git a/src/routes/(2)guides/(1)deployment-options/firebase.mdx b/src/routes/(2)guides/(1)deployment-options/firebase.mdx deleted file mode 100644 index 6cb1219b6..000000000 --- a/src/routes/(2)guides/(1)deployment-options/firebase.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: Firebase -category: Guides / Deployment -order: 3 -mainNavExclude: true -use_cases: >- - google cloud hosting, static hosting, firebase integration, web app - deployment, production hosting -tags: - - firebase - - google - - deployment - - hosting - - cli - - static -version: "1.0" -description: >- - Host your Solid application on Firebase with Google's infrastructure for - reliable static site hosting and easy deployment. ---- - -[Firebase](https://firebase.google.com/) is an all-in-one app development platform by Google, offering a range of services from real-time databases to user authentication. -For a detailed overview of the services available, you can visit [Firebase's documentation](https://firebase.google.com/docs). - -Before proceeding, make sure you've already set up a project in your Firebase console. -If you haven't, you can follow [Firebase's official guide](https://firebase.google.com/docs/projects/learn-more#creating-cloud-projects) to create a new Firebase project. - -## Using the Firebase CLI Tool - -1. Use your preferred package manager to install the Firebase command-line tool with one of the following commands: - -```package-install-global -firebase-tools -``` - -2. Execute the `firebase login` command to ensure that you're logged into the Firebase account associated with your project. - -3. In the root directory of your Solid project, create two new files: `firebase.json` and `.firebaserc`. - -- In `firebase.json`, add the following code: - -```json -{ - "hosting": { - "public": "dist", - "ignore": [] - } -} -``` - -- In `.firebaserc`, insert the following code (replace `` with your Firebase project ID): - -```bash frame="none" -{ - "projects": { - "default": "" - } -} -``` - -4. Run `npm run build` , followed by `firebase deploy` to build and deploy your project. - -Upon completion, a `Hosting URL` will be displayed, indicating the live deployment of your project. - - diff --git a/src/routes/(2)guides/(1)deployment-options/netlify.mdx b/src/routes/(2)guides/(1)deployment-options/netlify.mdx deleted file mode 100644 index 5526506c5..000000000 --- a/src/routes/(2)guides/(1)deployment-options/netlify.mdx +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: Netlify -category: Guides / Deployment -order: 4 -mainNavExclude: true -use_cases: >- - static site hosting, continuous deployment, git integration, web publishing, - jamstack hosting -tags: - - netlify - - deployment - - hosting - - git - - cli - - static -version: "1.0" -description: >- - Deploy Solid apps to Netlify with automatic builds from Git, instant - rollbacks, and powerful deployment features included. ---- - -[Netlify](https://www.netlify.com/) is a widely-used hosting platform suitable for various types of projects. -For detailed guidance on build procedures, deployment options, and the range of features available, you can visit the [Netlify documentation](https://docs.netlify.com/). - -## Using the Netlify web interface - -1. Begin by navigating to [Netlify's website](https://app.netlify.com/) and logging in or creating a new Netlify account. - Once logged in, you will be taken to your dashboard. Click the `New site from Git` button to start a new project. - - - -2. On the following page, choose "Connect to GitHub" or your preferred Git repository hosting service. - - - -3. After selecting your Solid project repository, you'll be directed to a configuration screen. - Update the "Publish directory" field from `netlify` to `dist`. Then, click "Deploy" to start the deployment process. - - - -4. Once the build and deployment are complete, you will be taken to a screen that displays the URL of your live site. - -## Using the Netlify CLI - -1. Install the Netlify CLI using your preferred package manager: - -```package-install-global -netlify-cli -``` - -**Note:** -Before proceeding, ensure that your Netlify account and team are fully set up. -This is crucial for a seamless project setup and deployment. - -2. Open your terminal, navigate to your project directory, and run the `netlify init` command. - Authenticate using one of the supported login options. - -3. Follow the on-screen instructions from the CLI. When prompted for the 'Directory to deploy,' specify `dist` — this is where Solid stores the built project files. - -After completing the process, your project will be deployed on Netlify and can be accessed via the provided URL. - - diff --git a/src/routes/(2)guides/(1)deployment-options/railway.mdx b/src/routes/(2)guides/(1)deployment-options/railway.mdx deleted file mode 100644 index cb51aa839..000000000 --- a/src/routes/(2)guides/(1)deployment-options/railway.mdx +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Railway -category: Guides / Deployment -order: 5 -mainNavExclude: true -use_cases: >- - web app deployment, cloud hosting, github deployment, production hosting, - quick deployment -tags: - - railway - - deployment - - hosting - - cloud - - github - - cli -version: "1.0" -description: >- - Deploy Solid projects to Railway platform with GitHub integration, custom - domains, and straightforward deployment process. ---- - -[Railway](https://railway.app/) is a well-known platform for deploying a variety of web and cloud-based projects. -For an in-depth look at the features offered by Railway, as well as detailed deployment guidelines, you can consult the [Railway documentation](https://docs.railway.app/). - -## Adjust the Start command - -To begin, you need to update the start command in your `package.json` file to make it compatible with Railway. -Change the start command to `npx http-server ./dist` instead of using `vite`. -This adjustment means you will need to build the app to generate the `dist` folder. - -For local development, continue using the original `dev` command. -Reserve the modified start command specifically for Railway deployments. -Below is an example of how your `package.json` may be configured: - -```jsonl -"scripts": { - "start": "npx http-server ./dist", - "dev": "vite", - "build": "vite build", - "serve": "vite preview", - "predeploy": "npm run build", - "deploy": "gh-pages -d build" -}, -``` - -## Using the Railway web interface - -1. Visit Railway's homepage and click "Start a New Project." - You will be redirected to connect with GitHub. - Log in or create an account using your GitHub credentials and authorize Railway to access your account. - - - -2. After authorization, choose the repository that has your Solid project. - During this step, you can also add any required environment variables. - - - -3. Once your project is configured, click "Deploy Now." - After a successful deployment, a confirmation screen will appear. - - - -4. Railway does not automatically assign a domain to your project. - To do this, go to the settings and manually generate a domain for your deployed project. - - - -Once a domain has been generated, your Solid project should be live. - -## Using the Railway CLI - -1. Using your preferred package manager and install the Railway CLI: - -```package-install-global -@railway/cli -``` - -2. Open your terminal and run the following command to log in: - -```bash frame="none" -railway login -``` - -3. You have the option to link your local Solid project to an existing Railway project using railway link. - Alternatively, you can create a new project with `railway init` and follow the on-screen prompts. - -4. To deploy your project to Railway, use the following command: - -```bash frame="none" -railway up -# or -railway up --detach # if you prefer to avoid logs -``` - -Your project will now be live on Railway. diff --git a/src/routes/(2)guides/(1)deployment-options/stormkit.mdx b/src/routes/(2)guides/(1)deployment-options/stormkit.mdx deleted file mode 100644 index c40eadd36..000000000 --- a/src/routes/(2)guides/(1)deployment-options/stormkit.mdx +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Stormkit -category: Guides / Deployment -order: 7 -mainNavExclude: true -use_cases: >- - spa deployment, serverless functions, static hosting, git deployment, - production hosting -tags: - - stormkit - - deployment - - hosting - - serverless - - spa - - static -version: "1.0" -description: >- - Deploy Solid apps as static sites or SPAs on Stormkit with serverless - functions support and Git provider integration. ---- - -[Stormkit](https://www.stormkit.io) is a deployment platform for static websites, single-page applications (SPAs), and serverless functions. - -1. Log in to Stormkit. - -2. Using the user interface, import your Solid project from one of the three supported Git providers (GitHub, GitLab, or Bitbucket). - -3. Navigate to the project’s production environment in Stormkit or create a new environment if needed. - -4. Verify the build command in your Stormkit configuration. By default, Stormkit CI will run `npm run build` but you can specify a custom build command on this page. - -5. Check output folder, unless its specified Stormkit will try to upload contents of build folder. - -6. Click the “Deploy Now” button to deploy your site. Stormkit CI will build your code and upload contents of it. - -Find more details on [Stormkit Documentation](https://stormkit.io/docs). diff --git a/src/routes/(2)guides/(1)deployment-options/vercel.mdx b/src/routes/(2)guides/(1)deployment-options/vercel.mdx deleted file mode 100644 index 8c78fa3fe..000000000 --- a/src/routes/(2)guides/(1)deployment-options/vercel.mdx +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Vercel -category: Guides / Deployment -order: 6 -mainNavExclude: true -use_cases: >- - deploying to production, hosting solid apps, ci/cd setup, automatic - deployments, serverless functions -tags: - - deployment - - hosting - - vercel - - production - - ci/cd - - serverless -version: "1.0" -description: >- - Deploy SolidStart apps to Vercel with automatic builds, serverless functions, - and GitHub integration for seamless production hosting. ---- - -[Vercel](https://vercel.com/) is a widely-used platform specialized in hosting frontend projects. -For detailed information regarding build and deployment instructions, as well as features they offer, please visit the [Vercel documentation](https://vercel.com/docs). - -## Using Vercel web interface - -1. Navigate to [vercel.com/login](https://vercel.com/login) to log in or create a new account. - Connect with your preferred Git repository hosting service. - - - -2. Once on the dashboard, click the button at the top right corner and choose "Add New Project." - On the next page, select "Continue with GitHub" or your preferred Git service. - - - -3. You will then see with a list of your repositories. - Use the search bar if needed to find the specific repository you want to deploy. - Click the "Import" button to proceed. - -4. After importing your Solid project repository, you will be taken to a configuration screen. - If your project requires any environment variables, add them in the designated field. - Click "Deploy" to start the deployment process. - - - -5. Once the build and deployment are finished, you will be redirected to a screen that displays a screenshot of your live site. - - - -## Using the Vercel CLI - -1. Install the Vercel CLI using your preferred package manager. - -```package-install-global -vercel -``` - -2. Open your terminal, navigate to your project directory, and run the following command to log in: - -```bash frame="none" -vercel -``` - -3. Follow the on-screen instructions from the CLI to finalize the deployment. - Once completed, your project will be live on Vercel and accessible via the provided URL. diff --git a/src/routes/(2)guides/(1)deployment-options/zerops.mdx b/src/routes/(2)guides/(1)deployment-options/zerops.mdx deleted file mode 100644 index 6bb237114..000000000 --- a/src/routes/(2)guides/(1)deployment-options/zerops.mdx +++ /dev/null @@ -1,181 +0,0 @@ ---- -title: Zerops -category: Guides / Deployment -order: 7 -mainNavExclude: true -use_cases: >- - deploying solid apps, static site hosting, ssr deployment, node.js hosting, - production deployment -tags: - - deployment - - hosting - - zerops - - static - - ssr - - node.js - - production -version: "1.0" -description: >- - Deploy SolidStart apps to Zerops cloud platform with support for both static - sites and SSR Node.js applications in production. ---- - -[Zerops](https://zerops.io) is a dev-first cloud platform that can be used to deploy both Static and SSR Solid Node.js Apps. - -For additional one-to-one support, details, and features, you can join the [Zerops Discord server](https://discord.gg/xxzmJSDKPT) and [visit the Zerops Docs](https://docs.zerops.io). - -Deploy and test Zerops Solid recipes with one click: - -- [Deploy Solid Node.js & Static Together](https://app.zerops.io/recipe/solidjs) - [Node.js](https://github.com/zeropsio/recipe-solidjs-nodejs) and [Static](https://github.com/zeropsio/recipe-solidjs-static). -- [Deploy Solid Node.js](https://app.zerops.io/recipe/solidjs-nodejs) - [Source Repository](https://github.com/zeropsio/recipe-solidjs-nodejs) -- [Deploy Solid Static](https://app.zerops.io/recipe/solidjs-static) - [Source Repository](https://github.com/zeropsio/recipe-solidjs-static) - -## Setting up an Account on Zerops - -1. Go to [Zerops Registration](https://app.zerops.io/registration) and sign up using GitHub, GitLab, or just your email. - -## Setting up your Project Infrastructure - -There are two ways to set up a Zerops project and a service: - -#### Using Project Add Wizard (GUI) - -1. Go to your [Zerops dashboard](https://app.zerops.io/dashboard/projects). -2. Add a new project using your sidebar. If you're in compact mode, click on your profile and then "Add new project." -3. You'll be redirected to a page where you can choose a service. - -##### For Static: - -1. Choose Static. -2. Scroll down and change the hostname to your preference. -3. Scroll down and click on the "Add New Static" button. - -##### For SSR - Node.js: - -1. Choose `Node.js` and select `version 20`. -2. Scroll down and change the hostname to your preference. -3. Scroll down and click on the "Add New Node.js" button. - -#### Using Project Import YAML - -**Note**: This is only used for project creation using YAML on the web interface—no need to add it to the project. - -1. Go to your [Zerops dashboard](https://app.zerops.io/dashboard/projects) and click on your profile icon if you are a new user. If not, check your sidebar and click on `Import Project`. - -##### Static: - -```yaml -project: - name: recipe-solidjs - -services: - - hostname: app - type: static - enableSubdomainAccess: true -``` - -##### SSR - Node.js: - -```yaml -project: - name: recipe-solidjs - -services: - - hostname: app - type: nodejs@20 - enableSubdomainAccess: true -``` - -## Add zerops.yml to your repository - -The `zerops.yml` configuration file is used to tell Zerops how to build and run your application, it should be placed at the root of your appplication's repository. - -Example for **SSR (Server-Side Rendering)** Apps: - -Set up the `zerops.yml` file in the root of your SSR project. Make sure the setup parameter's value is the same as the hostname of the service. - -```yaml -zerops: - - setup: app - build: - base: nodejs@latest - buildCommands: - - pnpm i - - pnpm build - deployFiles: - - .output - - node_modules - - public - - package.json - run: - base: nodejs@latest - ports: - - port: 3000 - httpSupport: true - start: pnpm start -``` - -Example for **SSG (Static Site Generation)** Apps: - -Set up the `zerops.yml` file in the root of your SSG project. Make sure the setup parameter's value is the same as the hostname of the service. - -```yaml -zerops: - - setup: app - build: - base: nodejs@latest - buildCommands: - - pnpm i - - pnpm build - deployFiles: - - dist/~ - run: - base: static -``` - -Push the changes to your GitHub/GitLab repository (necessary if you are planning to use GitHub/GitLab). - -## Deploying your apps - -### Triggering the pipeline automatically by connecting Github/Gitlab repository - -You can push your project by [Triggering the pipeline using Zerops CLI](#triggering-the-pipeline-using-githubgitlab) or by connecting the app service with your [GitHub](https://docs.zerops.io/references/github-integration/) / [GitLab](https://docs.zerops.io/references/gitlab-integration) repository from inside the service detail. - -### Triggering the pipeline manually using Zerops CLI - -To download the zCLI binary directly, use [zCLI/releases](https://github.com/zeropsio/zcli/releases) or: - -1. Install the Zerops CLI using Terminal. - -Linux/MacOS - -```bash -curl -L https://zerops.io/zcli/install.sh | sh -``` - -Windows - -```powershell -irm https://zerops.io/zcli/install.ps1 | iex -``` - -Npm - -```package-install-global -@zerops/zcli -``` - -2. Open Settings > [Access Token Management](https://app.zerops.io/settings/token-management) in the Zerops app and generate a new access token. -3. Log in using your access token with the following command: - -```bash -zcli login -``` - -4. Navigate to the root of your app (where zerops.yml is located) and run the following command in Terminal to trigger the deploy: - -```bash -zcli push -``` - -Check the official docs if you need more advanced use-cases for [Zerops Docs](http://docs.zerops.io/). diff --git a/src/routes/(2)guides/(1)state-management.mdx b/src/routes/(2)guides/(1)state-management.mdx deleted file mode 100644 index 099dbd7ee..000000000 --- a/src/routes/(2)guides/(1)state-management.mdx +++ /dev/null @@ -1,366 +0,0 @@ ---- -title: State management -category: Guides -order: 2 -use_cases: >- - managing app state, component communication, data flow, reactive updates, - shared state, derived values -tags: - - state - - signals - - reactivity - - data-flow - - memos - - effects - - management -version: "1.0" -description: >- - Learn Solid's state management with signals, derived values, memos, and - effects for reactive data flow and component updates. ---- - -State management is the process of handling and manipulating data that affects the behavior and presentation of a web application. -To build interactive and dynamic web applications, state management is a critical aspect of development. -Within Solid, state management is facilitated through the use of reactive primitives. - -These state management concepts will be shown using a basic counter example: - -```jsx -import { createSignal } from "solid-js"; - -function Counter() { - const [count, setCount] = createSignal(0); - - const increment = () => { - setCount((prev) => prev + 1); - }; - - return ( - <> -
    Current count: {count()}
    - - - ); -} -``` - -There are 3 elements to state management: - -1. **State (`count`)**: The _data_ that is used to determine what content to display to the user. - -2. **View (`
    {count()}
    `)**: The _visual representation_ of the state to the user. - -3. **Actions (`increment`)**: Any event that _modifies_ the state. - -These elements work together to create a "one way data flow". -When actions modify the state, the view is updated to show the current state to the user. -One way data flow simplifies the management of data and user interactions, which provides a more predictable and maintainable application. - -## Managing basic state - -State is the source of truth for the application, and is used to determine what content to display to the user. -State is represented by a [signal](/concepts/signals), which is a reactive primitive that manages state and notifies the UI of any changes. - -To create a piece of state, you use the [`createSignal`](/reference/basic-reactivity/create-signal) function and pass in the initial value of the state: - -```jsx -import { createSignal } from "solid-js"; - -const [count, setCount] = createSignal(0); -``` - -To access the current value of the state, you call the signal's getter function: - -```jsx -console.log(count()); // 0 -``` - -To update the state, you use the signal's setter function: - -```jsx -setCount((prev) => prev + 1); - -console.log(count()); // 1 -``` - -With signals, you can create and manage state in a simple and straightforward manner. -This allows you to focus on the logic of your application, rather than the complexities of state management. -Additionally, signals are reactive, which means as long as it is accessed within a [tracking scope](/concepts/intro-to-reactivity#tracking-changes), it will always be up to date. - -## Rendering state in the UI - -To achieve a dynamic user interface, the UI must be able to reflect the current state of the data. -The UI is the visual representation of the state to the user, and is rendered using JSX. -JSX provides a tracking scope, which keeps the view in sync with the state. - -Revisiting the `Counter` component presented earlier, rendering the current state of `count` is done within the return body using JSX: - -```jsx -return ( - <> -
    Current count: {count()}
    - - -); -``` - -To render the current state of `count`, the JSX expression `{count()}` is used. -The curly braces indicate that the expression is a JavaScript expression, and the parentheses indicate that it is a function call. -This expression is representative of a getter function for `count` and will retrieve the current state value. -When the state is updated, the UI will be re-rendered to reflect the new state value. - -Components in Solid only run once upon their initialization. -After this initial render, if any changes are made to the state, only the portion of the DOM that is directly associated with the signal change will be updated. - -The ability to update only the relevant portions of the DOM is a key feature of Solid that allows for performant and efficient UI updates. -This is known as [fine-grained reactivity](/advanced-concepts/fine-grained-reactivity). -Through reducing the re-rendering of entire components or larger DOM segments, UI will remain more efficient and responsive for the user. - -## Reacting to changes - -When the state is updated, any updates are reflected in the UI. -However, there may be times when you want to perform additional actions when the state changes. - -For example, in the `Counter` component, you may want to display the doubled value of `count` to the user. -This can be achieved through the use of [effects](/concepts/effects), which are reactive primitives that perform side effects when the state changes: - -```jsx -import { createSignal, createEffect } from "solid-js"; - -function Counter() { - const [count, setCount] = createSignal(0); - const [doubleCount, setDoubleCount] = createSignal(0); // Initialize a new state for doubleCount - - const increment = () => { - setCount((prev) => prev + 1); - }; - - createEffect(() => { - setDoubleCount(count() * 2); // Update doubleCount whenever count changes - }); - - return ( - <> -
    Current count: {count()}
    -
    Doubled count: {doubleCount()}
    // Display the doubled count - - - ); -} -``` - -The [`createEffect`](/reference/basic-reactivity/create-effect) function sets up a function to perform side effects whenever the state is modified. -Here, a side-effect refers to operations or updates that affect state outside of the local environment - like modifying a global variable or updating the DOM - triggered by those state changes. - -In the `Counter` component, a `createEffect` function can be used to update the `doubleCount` state whenever the `count` state changes. -This keeps the `doubleCount` state in sync with the `count` state, and allows the UI to display the doubled value of `count` to the user. - -View this example of [`doubleCount` in a `createEffect` in the Solid Playground example](https://playground.solidjs.com/anonymous/b05dddaa-e62a-4c56-b745-5704f3a40194). - -```html tab title="First render" -Current count: 0 Doubled count: 0 -``` - -```html tab title="After increment" -Current count: 1 Doubled count: 2 -``` - -## Derived state - -When you want to calculate new state values based on existing state values, you can use derived state. -This is a useful pattern when you want to display a transformation of a state value to the user, but do not want to modify the original state value or create a new state value. - -Derived values can be created using a signal within a function, which can be referred to as a [derived signal](/concepts/derived-values/derived-signals). - -This approach can be used to simplify the `doubleCount` example above, where the additional signal and effect can be replaced with a derived signal: - -```jsx del={5, 11-13} ins={15} -import { createSignal } from "solid-js"; - -function Counter() { - const [count, setCount] = createSignal(0); - const [doubleCount, setDoubleCount] = createSignal(0); - - const increment = () => { - setCount((prev) => prev + 1); - }; - - createEffect(() => { - setDoubleCount(count() * 2); // Update doubleCount whenever count changes - }); - - const doubleCount = () => count() * 2; - - return ( - <> -
    Current count: {count()}
    -
    Doubled count: {doubleCount()}
    - - - ); -} -``` - -While this approach works for simple use cases, if `doubleCount` is used several times within a component or contains a computationally expensive calculation, it can lead to performance issues. - -The derived signal would be re-evaluated not just each time `count` is changed, but also for each use of `doubleCount()`. - -```jsx del={10} ins={11-14, 20-21} -import { createSignal } from "solid-js"; - -function Counter() { - const [count, setCount] = createSignal(0); - - const increment = () => { - setCount(count() + 1); - }; - - const doubleCount = () => count() * 2; - const doubleCount = () => { - console.log("doubleCount called"); - return count() * 2; - }; - - return ( - <> -
    Current count: {count()}
    -
    Doubled count: {doubleCount()}
    -
    Doubled count: {doubleCount()}
    -
    Doubled count: {doubleCount()}
    - - - ); -} -``` - -```shellsession title="Console output" -doubleCount called -doubleCount called -doubleCount called -``` - -For cases like this, you can use [Memos](/concepts/derived-values/memos) to store the value of `doubleCount`, which are also referred to as a memoized or cached value. -When using a memo, the calculation will only run **once** when the value of `count` changes and can be accessed multiple times without re-evaluating for each additional use. - -Using the [`createMemo`](/reference/basic-reactivity/create-memo) function, you can create a memoized value: - -```jsx ins={15-18, 26-28} ins=", createMemo" -import { createSignal, createMemo } from "solid-js"; - -function Counter() { - const [count, setCount] = createSignal(0); - - const increment = () => { - setCount((prev) => prev + 1); - }; - - const doubleCount = () => { - console.log("doubleCount called"); - return count() * 2; - }; - - const doubleCountMemo = createMemo(() => { - console.log("doubleCountMemo called"); - return count() * 2; - }); - - return ( - <> -
    Current count: {count()}
    -
    Doubled count: {doubleCount()}
    -
    Doubled count: {doubleCount()}
    -
    Doubled count: {doubleCount()}
    -
    Doubled count: {doubleCountMemo()}
    -
    Doubled count: {doubleCountMemo()}
    -
    Doubled count: {doubleCountMemo()}
    - - - ); -} -``` - -```shellsession title="Console output" -doubleCountMemo called -doubleCount called -doubleCount called -doubleCount called -``` - -While accessed multiple times, the `doubleCountMemo` will only re-evaluate and log once. -This is different from the derived signal, `doubleCount`, which is re-evaluated for each time it is accessed. - -View a similar [example comparing a derived signal and a memo in the Solid Playground](https://playground.solidjs.com/anonymous/288736aa-d5ba-45f7-a01f-1ac3dcb1b479). - -## Lifting state - -When you want to share state between components, you can lift state up to a common ancestor component. -While state is not tied to components, you may want to link multiple components together in order to access and manipulate the same piece of state. -This can keep things synchronized across the [component tree](/concepts/components/basics#component-trees) and allow for more predictable state management. - -For example, in the `Counter` component, you may want to display the doubled value of `count` to the user through a separate component: - -```jsx -import { createSignal, createEffect, createMemo } from "solid-js"; - -function App() { - const [count, setCount] = createSignal(0); - const [doubleCount, setDoubleCount] = createSignal(0); - const squaredCount = createMemo(() => count() * count()); - - createEffect(() => { - setDoubleCount(count() * 2); - }); - - return ( - <> - - - - ); -} - -function Counter(props) { - const increment = () => { - props.setCount((prev) => prev + 1); - }; - - return ; -} - -function DisplayCounts(props) { - return ( -
    -
    Current count: {props.count}
    -
    Doubled count: {props.doubleCount}
    -
    Squared count: {props.squaredCount}
    -
    - ); -} - -export default App; -``` - -To share the `count` state between the `Counter` and `DisplayCounts` components, you can lift the state up to the `App` component. -This allows the `Counter` and `DisplayCounts` functions to access the same piece of state, but also allows the `Counter` component to update the state through the `setCount` setter function. - -When sharing state between components, you can access the state through [`props`](/concepts/components/props). -Props values that are passed down from the parent component are read-only, which means they cannot be directly modified by the child component. -However, you can pass down setter functions from the parent component to allow the child component to indirectly modify the parent's state. - -:::note -To encourage one-way data flow, props are passed as read-only or immutable values from the parent to child components. - -There are [specific utility functions for props](/concepts/components/props), however, that offer methods to modify props values. - -::: - -## Managing complex state - -As applications grow in size and complexity, lifting state can become difficult to manage. -To avoid the concept of prop drilling, which is the process of passing props through multiple components, Solid offers [stores](/concepts/stores) to manage state in a more scalable and maintainable manner. - -To learn more about managing complex state, navigate to the [complex state management page](/guides/complex-state-management). diff --git a/src/routes/(2)guides/(2)routing-and-navigation.mdx b/src/routes/(2)guides/(2)routing-and-navigation.mdx deleted file mode 100644 index 297161c48..000000000 --- a/src/routes/(2)guides/(2)routing-and-navigation.mdx +++ /dev/null @@ -1,530 +0,0 @@ ---- -title: Routing & navigation -category: Guides -order: 4 -use_cases: >- - page navigation, url routing, spa routing, dynamic routes, nested layouts, - route parameters, lazy loading pages -tags: - - routing - - navigation - - routes - - spa - - lazy-loading - - parameters - - layouts -version: "1.0" -description: >- - Implement client-side routing in Solid apps with dynamic routes, nested - layouts, route parameters, and lazy-loaded components. ---- - -[Solid Router](/solid-router) simplifies routing in Solid applications to help developers manage navigation and rendering by defining routes using JSX or objects passed via props. - -## Getting started - -**1. Install the router** - -This package is not included by default. - -```package-install -@solidjs/router -``` - -**2. Setup the `` component** - -Start your application by rendering the [Router](/solid-router/reference/components/router) component. -This component will match the URL to display the desired page. - -```jsx -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -render(() => , document.getElementById("root")); -``` - -**3. Provide a root level layout** - -This layout will not update on page change and is the ideal place for top-level navigation and [Context Providers](/concepts/context). - -```jsx -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -const App = (props) => ( - <> -

    Site Title

    - {props.children} - -); - -render(() => , document.getElementById("root")); -``` - -**4. Add routes** - -Each route is added to the `Router` using the [`Route`](/solid-router/reference/components/route) component. -Here, you specify a path and a component to render once the user navigates to that path. - -```jsx -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -import Home from "./pages/Home"; -import Users from "./pages/Users"; - -const App = (props) => ( - <> -

    Site Title

    - {props.children} - -); - -render( - () => ( - - - - - ), - document.getElementById("root") -); -``` - -**5. Create a CatchAll route (404 page)** - -A catchall route can be used for pages not found at any nested level of the router. -Using `*` will retrieve the rest of the path. -Optionally, you can also add a parameter name. - -```jsx -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -import Home from "./pages/Home"; -import Users from "./pages/Users"; -import NotFound from "./pages/NotFound"; - -const App = (props) => ( - <> -

    Site Title

    - {props.children} - -); - -render( - () => ( - - - - - - ), - document.getElementById("root") -); -``` - -**6. Create links to your routes** - -The [``](/solid-router/reference/components/a) component provides navigation to an application's routes. -Alternatively, you can use the [native anchor tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a). -However, the `` component provides additional functionality including properties for CSS, `inactiveClass` and `activeClass`. - -```jsx -import { render } from "solid-js/web"; -import { Router, Route, A } from "@solidjs/router"; - -import Home from "./pages/Home"; -import Users from "./pages/Users"; -import NotFound from "./pages/NotFound"; - -const App = (props) => ( - <> - -

    Site Title

    - {props.children} - -); - -render( - () => ( - - - - - - ), - document.getElementById("root") -); -``` - -## Lazy-loading route components - -The [`lazy`](/reference/component-apis/lazy) function postpones the loading of a component until it is navigated to. - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -const Users = lazy(() => import("./pages/Users")); -const Home = lazy(() => import("./pages/Home")); - -const App = (props) => ( - <> -

    Site Title

    - {props.children} - -); - -render( - () => ( - - - - - ), - document.getElementById("root") -); -``` - -## Dynamic routes - -If a path is unknown ahead of time, you can treat part of the path as a flexible parameter. - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -const Users = lazy(() => import("./pages/Users")); -const User = lazy(() => import("./pages/User")); -const Home = lazy(() => import("./pages/Home")); - -render( - () => ( - - - - - - ), - document.getElementById("root") -); -``` - -The colon indicates that `id` can be any string, and as long as the URL fits that pattern, the `` component will show. - -You can then access that `id` from within a route component with [`useParams`](/solid-router/reference/primitives/use-params). - -**Note on animation/transitions**: -Routes that share the same path will be treated as the same route. -If you want to force re-render, you can wrap your component in a keyed [``](/reference/components/show): - -```jsx - - - -``` - -### Accessing parameters - -In cases where you may need to access a dynamic route's parameters within your components, the [`useParams`](/solid-router/reference/primitives/use-params) primitive is available. -Once the parameters have been accessed using `useParams`, they can be used within your component: - -```jsx -import { useParams } from "@solidjs/router"; - -const User = () => { - const params = useParams(); // Retrieve the dynamic route parameters - // Now you can access the id parameter as params.id - - return ( -

    - This is the user with the id of {params.id} -

    - ); -}; -``` - -`useParams` can be especially useful with other Solid primitives, such as [`createResource`](/reference/basic-reactivity/create-resource) and [`createSignal`](/reference/basic-reactivity/create-signal), which can create dynamic behaviors based on the route parameters. - -```jsx -import { createResource } from "solid-js"; -import { useParams } from "@solidjs/router"; - -async function fetchUser(id) { - const response = await fetch( - `https://jsonplaceholder.typicode.com/users/${id}` - ); - return response.json(); -} - -const User = () => { - const params = useParams(); - const [data] = createResource(() => params.id, fetchUser); // Pass the id parameter to createResource - - return ( -
    - Loading...

    }> -
    -

    Name: {data().name}

    -

    Email: {data().email}

    -

    Phone: {data().phone}

    -
    -
    -
    - ); -}; -``` - -Every time the `id` parameter changes in this example, the `fetchUser` function is called to fetch the new user data. - -### Validating routes - -Each path parameter can be validated using a `MatchFilter`. -Instead of checking for the presence of a parameter, this allows for more complex routing descriptions: - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route, type MatchFilters } from "@solidjs/router"; - -const User = lazy(() => import("./pages/User")); - -const filters: MatchFilters = { - parent: ["mom", "dad"], // allow enum values - id: /^\d+$/, // only allow numbers - withHtmlExtension: (v: string) => v.length > 5 && v.endsWith(".html"), // only `*.html` extensions wanted -}; - -render(() => ( - - - -), document.getElementById("root")); -``` - -In this example, the `matchFilters` prop provides a way to validate the `parent`, `id` and `withHtmlExtension` parameters against the filters defined in `filters`. -If the validation fails, the route will not match. - -In this example: - -- `/users/mom/123/contact.html` will match, -- `/users/dad/123/about.html` will match, -- `/users/aunt/123/contact.html` will **not** match as `:parent` is not 'mom' or 'dad', -- `/users/mom/me/contact.html` will **not** match as `:id` is not a number, -- `/users/dad/123/contact` will **not** match as `:withHtmlExtension` is missing `.html`. - -### Optional parameters - -Parameters can be specified as optional by adding a question mark to the end of the parameter name: - -```jsx -// Matches stories and stories/123 but not stories/123/comments - -``` - -### Wildcard routes - -To match any descendent routes within a given path, you can use the wildcard token (`*`). -This can be used to represent any value in that segment of the path. - -```jsx -// Will match any path beginning with foo (eg. foo/, foo/a/, foo/a/b/c) - -``` - -To expose the wildcard portion to the component as a parameter, you can name it: - -```jsx - -``` - -Wildcard tokens **must** be the last part of the path; `foo/*any/bar` will not create any routes. - -### Multiple paths - -The `Routes` component also supports defining multiple paths using an array. -This avoids a route rerendering when switching between two or more locations that it matches: - -```jsx -// Navigating from "/login" to "/register" will not cause the component to re-render - -``` - -## Nested routes - -Only leaf `` nodes (the innermost `` components) are given a route. - -```jsx - - - -``` - -The following two route definitions both match the same URL `/users/:id` and render the same component: - -```jsx - - - - - -``` - -If you want to make the parent its own route, you have to specify it separately: - -```jsx - - - -// or - - - - - -``` - -You can also take advantage of nesting by using `props.children` passed to the route component. - -```jsx -function PageWrapper(props) { - return ( -
    -

    We love our users!

    - {props.children} - Back Home -
    - ); -} - - - - -; -``` - -The routes are still configured the same, however now their components will appear inside the parent component where the `props.children` is declared. - -Routes can also be nested indefinitely. -This example will only render the route `/layer1/layer2`, which will be nested in 3 divs. - -```jsx -
    Outermost layer starts here {props.children}
    } -> -
    Second layer {props.children}
    } - > -
    Innermost layer
    } /> -
    -
    -``` - -## Preload functions - -With preload functions, data fetching is started parallel to loading the route, so it can be used as soon as possible. -The preload function prevents this by being called once the Route is loaded, or eagerly if links are hovered. - -As the only argument, the preload function is passed an object that is used to access route information: - -```jsx -import { lazy } from "solid-js"; -import { Route } from "@solidjs/router"; - -const User = lazy(() => import("./pages/users/[id].js")); - -// preload function -function preloadUser({ params, location }) { - // do preload -} -``` - -The preload function is then passed in the `` definition: - -```jsx - -``` - ---- - -You can export preload functions and data wrappers that correspond to routes from a dedicated `[route].data.js` or `[route].data.ts` file. -This pattern provides a way to import the data function without loading anything else. - -```tsx title="src/pages/users/[id].data.js" -import { query } from "@solidjs/router"; - -export const getUser = query(async (id) => { - return (await fetch(`https://swapi.tech/api/people/${id}/`)).json(); -}, "getUser"); - -export function preloadUser({ params, location, intent }) { - return getUser(params.id); -} -``` - -`preloadUser` is passed an object which contains `params`, `location` and `intent`. - -Please note that while it is best practice to name these files as `[id].data.js`, you can still name them as `route.data.js`. - -The value of a preload function is passed to the page component when called at any time other than "preload". -This means you can initialize the page, or use [Data APIs](/solid-router/reference/data-apis/create-async). - -:::note -To prevent a fetch from happening more than once, or to trigger a refetch, you -can use the [`query` function](/solid-router/reference/data-apis/query). -::: - -```jsx title="index.jsx" -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; -import { preloadUser } from "./pages/users/[id].data.js"; - -const Home = lazy(() => import("./pages/Home")); -const User = lazy(() => import("./pages/users/[id]")); - -render( - () => ( - - - - - ), - document.getElementById("root") -); -``` - -`[id].jsx` contains the component that gets rendered. -When you wrap the function within [`createAsync`](/solid-router/reference/data-apis/create-async) with the imported function, it will yield [a signal](/concepts/signals) once the anticipated promise resolves. - -```tsx title="[id].tsx" -import { createAsync } from "@solidjs/router"; -import { getUser } from "./[id].data"; - -export default function Users(props) { - console.log("Users.props", props); - const user = createAsync(() => getUser(props.params.id)); - return ( - <> -

    User

    -
    -
    {JSON.stringify(user(), null, 2)}
    -
    - - ); -} -``` - -To learn more about routing your Solid applications, visit the [Solid Router documentation](/solid-router). diff --git a/src/routes/(2)guides/(3)complex-state-management.mdx b/src/routes/(2)guides/(3)complex-state-management.mdx deleted file mode 100644 index 8a93d3902..000000000 --- a/src/routes/(2)guides/(3)complex-state-management.mdx +++ /dev/null @@ -1,378 +0,0 @@ ---- -title: Complex state management -category: Guides -order: 5 -use_cases: >- - scaling applications, multiple components, backend communication, state - synchronization, prop drilling, shared state -tags: - - stores - - state - - context - - scaling - - components - - management -version: "1.0" -description: >- - Master complex state management in Solid using stores and context to build - scalable, maintainable applications efficiently. ---- - -As applications grow and start to involve many components, more intricate user interactions, and possibly communication with backend services, you may find that staying organized with more [basic state management methods](/guides/state-management) can become difficult to maintain. - -Consider this example: - -```jsx -import { For, createSignal, Show, createMemo } from "solid-js"; - -const App = () => { - const [tasks, setTasks] = createSignal([]); - const [numberOfTasks, setNumberOfTasks] = createSignal(tasks.length); - const completedTasks = createMemo(() => - tasks().filter((task) => task.completed) - ); - let input; - - const addTask = (text) => { - setTasks([...tasks(), { id: tasks().length, text, completed: false }]); - setNumberOfTasks(numberOfTasks() + 1); - }; - const toggleTask = (id) => { - setTasks( - tasks().map((task) => - task.id !== id ? task : { ...task, completed: !task.completed } - ) - ); - }; - - return ( - <> -

    My list

    - You have {numberOfTasks()} task(s) today! -
    - - -
    - - {(task) => { - const { id, text } = task; - console.log(`Creating ${text}`); - return ( -
    - - - {text} - -
    - ); - }} -
    - - ); -}; - -export default App; -``` - -There are several challenges to managing state in this way: - -- Increased verbosity with the multiple `createSignal` calls for `tasks`, `numberOfTasks`, as well as a `createMemo` function for `completedTasks`. - Additionally, with each state update, there requires manual updates to other related states which risks the application becoming out of sync. - -- While Solid is optimized, this components design leads to frequent recalculations, such as updating `completedTasks` with every toggle action, which can negatively impact performance. - In addition, the dependence on the component's logic on the current state for `numberOfTasks` and `completedTasks` can complicate code understanding. - -As an application like this scales, managing state in this manner becomes even more complex. -Introducing other dependent state variables would require updates across the _entire_ component which would likely introduce more errors. -This would likely make it more difficult to separate specific functionalities into distinct, reusable components without transferring a substantial portion of state management logic, as well. - -## Introducing stores - -Through recreating this list using Stores, you will see how stores can improve the readability and management of your code. - -If you're new to the concept of stores, see the [stores section](/concepts/stores). - -## Creating a store - -To reduce the amount of signals that were used in the original example, you can do the following using a store: - -```jsx -import { createStore } from "solid-js/store"; - -const App = () => { - const [state, setState] = createStore({ - tasks: [], - numberOfTasks: 0, - }); -}; - -export default App; -``` - -Through using a store, you no longer need to keep track of separate signals for `tasks`, `numberOfTasks`, and `completedTasks`. - -## Accessing state values - -Once you have created your store, the values can be accessed directly through the first value returned by the `createStore` function: - -```jsx -import { createStore } from "solid-js/store"; - -const App = () => { - const [state, setState] = createStore({ - tasks: [], - numberOfTasks: 0, - }); - return ( - <> -

    My Task List for Today

    - You have {state.numberOfTasks} task(s) for today! - - ); -}; - -export default App; -``` - -Through `state.numberOfTasks`, the display will now show the store's value held in the `numberOfTasks` property. - -## Making changes to the store - -When you want to modify your store, you use the second element returned by the `createStore` function. -This element allows you to make modifications to the store, letting you both add new properties and update existing ones. -However, because properties within a store are created lazily, setting a property in the component function body without creating a tracking scope will **not** update the value. -To create the signal so it reactively updates, you have to access the property within a tracking scope, such as using a [`createEffect`](/reference/basic-reactivity/create-effect): - -```jsx -// not reactive -setState("numberOfTasks", state.tasks.length); - -// reactive -createEffect(() => { - setState("numberOfTasks", state.tasks.length); -}); -``` - -### Adding to an array - -To add an element to an array, in this case the new task, you can append to the next index of the array through `state.tasks.length`. -By pinpointing the `tasks` key in combination with the upcoming position, the new task is added to the end of the array. - -```jsx -const addTask = (text) => { - setState("tasks", state.tasks.length, { - id: state.tasks.length, - text, - completed: false, - }); -}; -``` - -The setter in stores follow [path syntax](/concepts/stores#path-syntax-flexibility): `setStore("key", value)`. -In the `addTask` function the `tasks` array is appended through `setState("tasks", state.tasks.length, { id: state.tasks.length, text, completed: false })`, an example of this in action. - -#### Mutating state with `produce` - -In situations where you need to make multiple `setState` calls and target multiple properties, you can simplify your code and improve readability by using Solid's [`produce`](/concepts/stores#store-updates-with-produce) utility function. - -Something such as toggle function: - -```jsx -const toggleTask = (id) => { - const currentCompletedStatus = state.tasks[id].completed; - setState( - "tasks", - (task) => task.id === id, - "completed", - !currentCompletedStatus - ); -}; -``` - -Can be simplified using `produce`: - -```jsx -import { produce } from "solid-js/store"; - -const toggleTask = (id) => { - setState( - "tasks", - (task) => task.id === id, - produce((task) => { - task.completed = !task.completed; - }) - ); -}; - -// You can also rewrite the `addTask` function through produce -const addTask = (text) => { - setState( - "tasks", - produce((task) => { - task.push({ id: state.tasks.length, text, completed: false }); - }) - ); -}; -``` - -Read about some of the other [advantages to using `produce`](/concepts/stores#store-updates-with-produce). - - :::note - Another benefit to working with `produce` is that it offers a way to modify a store without having to make multiple `setStore` calls. - -```jsx -// without produce -batch(() => { - setState(0, "text", "I'm updated text"); - setState(0, "completed", true); -}); - -// with produce -setState( - 0, - produce((task) => { - task.text = "I'm updated text"; - task.completed = true; - }) -); -``` - - ::: - -The updated example: - -```jsx -import { For, createEffect, Show } from "solid-js"; -import { createStore, produce } from "solid-js/store"; - -const App = () => { - let input; // lets you target the input value - const [state, setState] = createStore({ - tasks: [], - numberOfTasks: 0, - }); - - const addTask = (text) => { - setState("tasks", state.tasks.length, { - id: state.tasks.length, - text, - completed: false, - }); - }; - - const toggleTask = (id) => { - setState( - "tasks", - (task) => task.id === id, - produce((task) => { - task.completed = !task.completed; - }) - ); - }; - - createEffect(() => { - setState("numberOfTasks", state.tasks.length); - }); - - return ( - <> -
    -

    My Task List for Today

    - You have {state.numberOfTasks} task(s) for today! -
    - - - - {(task) => { - const { id, text } = task; - return ( -
    - toggleTask(task.id)} - /> - {text} -
    - ); - }} -
    - - ); -}; - -export default App; -``` - -## State sharing - -As applications grow and become more complex, sharing state between components can become a challenge. -Passing state and functions from parent to child components, especially across multiple levels, is commonly referred to as "prop drilling". -Prop drilling can lead to verbose, hard-to-maintain code, and can make the data flow in an application more difficult to follow. -To solve this problem and allow for a more scalable and maintainable codebase, Solid provides [context](/concepts/context). - -To use this, you need to create a context. -This context will have a default value and can be consumed by any _descendant_ component. - -```jsx -import { createContext } from "solid-js"; - -const TaskContext = createContext(); -``` - -Your components will be wrapped with the `Provider` from the context, and passed with the values that you wish to share. - -```jsx -import { createStore } from "solid-js/store"; - -const TaskApp = () => { - const [state, setState] = createStore({ - tasks: [], - numberOfTasks: 0, - }); - - return ( - - {/* Your components */} - - ); -}; -``` - -In any descendent component, you can consume the context values using `useContext`: - -```jsx -import { useContext } from "solid-js"; - -const TaskList = () => { - const { state, setState } = useContext(TaskContext); - - // Now you can use the shared state and functions -}; -``` - -For a deeper dive, please refer to our dedicated [page on context](/concepts/context). diff --git a/src/routes/(2)guides/(4)fetching-data.mdx b/src/routes/(2)guides/(4)fetching-data.mdx deleted file mode 100644 index bbc6bccac..000000000 --- a/src/routes/(2)guides/(4)fetching-data.mdx +++ /dev/null @@ -1,210 +0,0 @@ ---- -title: Fetching data -category: Guides -order: 3 -use_cases: >- - api calls, async data loading, server communication, external data fetching, - loading states, error handling -tags: - - data - - fetching - - async - - api - - createresource - - suspense - - loading -version: "1.0" -description: >- - Master data fetching in Solid with createResource for async operations, - loading states, error handling, and Suspense boundaries. ---- - -For most modern web applications, data fetching is a common task. -Solid has a built-in utility, `createResource` , that was created to simplify data fetching. - -## What is `createResource` ? - -`createResource` is a specialized [signal](/concepts/signals) designed specifically for managing asynchronous data fetching. -It wraps around the async operations, providing a way to handle various states: loading, success, and error. - -This function is non-blocking, meaning that `createResource` guarantees that the application remains responsive, even during the retrieval of information. -Because of this, common pitfalls of traditional async handling, such as unresponsive UIs during data fetching can be avoided. - -## Using `createResource` - -`createResource` requires a function that returns a promise as its argument. -Upon the call, `createResource` returns a signal which has reactive properties like loading, error, latest, etc. -These properties can be used to conditionally render JSX based on the current reactive state. - -The fetcher function that is created makes a call to get a user, which is then passed in as an argument to `createResource`. - -The signal returned from the `createResource` provides the properties that can assist with conditional rendering based on the current reactive state: - -- `state`: The current status of the operation (`unresolved`, `pending`, `ready`, `refreshing`, or `errored`). -- `loading`: Indicates that the operation is currently in progress via a `boolean`. -- `error`: If the operation fails for any reason, this property will contain information about this error. - It may be a string with an error message, or an object with more detailed information. -- `latest`: The most recent data or result returned from the operation. - -When there is a change in the source signal, an internal fetch process is triggered to retrieve new data based on this change. - -```jsx -import { createSignal, createResource, Switch, Match, Show } from "solid-js"; - -const fetchUser = async (id) => { - const response = await fetch(`https://swapi.dev/api/people/${id}/`); - return response.json(); -}; - -function App() { - const [userId, setUserId] = createSignal(); - const [user] = createResource(userId, fetchUser); - - return ( -
    - setUserId(e.currentTarget.value)} - /> - -

    Loading...

    -
    - - - Error: {user.error} - - -
    {JSON.stringify(user())}
    -
    -
    -
    - ); -} -``` - -Whenever the signal value, `userId`, changes, the internal fetch method `fetchUser` gets triggered. -The properties of the `user` resource allow for conditional rendering based on the different states of the fetch process. - -The `Switch/Match` construct provides one way to manage these conditions. -When the fetch succeeds and user data is retrieved, the `user()` condition becomes active, and its related block executes. -However, if there's an error while fetching, the `user.error` block becomes `true`, leading to its corresponding `Match` block being shown. - -:::tip - -If you anticipate errors, you may want to wrap `createResource` in an [ErrorBoundary](/reference/components/error-boundary). - -::: - -In addition to the `error` property, the `loading` property offers a way to display a loading state to the user during the fetch operation. - -## Calling multiple async events - -Although you can use `createResource` independently, Solid provides an alternative method for synchronizing the display of multiple asynchronous events. -`Suspense` is a component in Solid designed to act as a boundary. -It allows you to display a fallback placeholder while waiting for all asynchronous events to resolve, preventing the display of partially loaded content: - -```jsx -import { - createSignal, - createResource, - Switch, - Match, - Suspense, -} from "solid-js"; - -const fetchUser = async (id) => { - const response = await fetch(`https://swapi.dev/api/people/${id}/`); - return response.json(); -}; - -function App() { - const [userId, setUserId] = createSignal(); - const [user] = createResource(userId, fetchUser); - - return ( -
    - setUserId(e.currentTarget.value)} - /> - Loading...
    }> - - - Error: {user.error.message} - - -
    {JSON.stringify(user())}
    -
    -
    - -
    - ); -} -``` - -`Suspense` has the ability to identify asynchronous reads within its descendants and act accordingly. -This feature helps to remove any intermediate components that may otherwise be displayed during partial loading states. -Additionally, you can nest as many components as needed within `Suspense` but only the closest ancestor will switch to the `fallback` state when a loading state is detected. - - - -## Dynamic data handling - -With the second output of `createResource`, there are 2 powerful methods designed to enhance and simplify some complex aspects of data management: - -### `mutate` - -In situations where immediate feedback or responsiveness is important, the `mutate` method offers "optimistic mutations." -These mutations provide instant feedback, even while background processes, such as server confirmations, are still in progress. - -This functionality is particularly valuable in applications like task lists. -For example, when users input a new task and click the `Add` button, the list will refresh immediately, regardless of the ongoing data communication with the server. - -```jsx -import { For, createResource } from "solid-js"; - -function TodoList() { - const [tasks, { mutate }] = createResource(fetchTasksFromServer); - - return ( - <> -
      - {(task) =>
    • {task.name}
    • }
      -
    - - - ); -} -``` - -### `refetch` - -When real-time feedback is necessary, the `refetch` method can be used to reload the current query regardless of any changes. -This method can be particularly useful when data is constantly evolving, such as with real-time financial applications. - -```jsx -import { createResource, onCleanup } from "solid-js"; - -function StockPriceTicker() { - const [prices, { refetch }] = createResource(fetchStockPrices); - - const timer = setInterval(() => { - refetch(); - }, 1000); - onCleanup(() => clearInterval(timer)); -} -``` diff --git a/src/routes/(2)guides/(5)testing.mdx b/src/routes/(2)guides/(5)testing.mdx deleted file mode 100644 index 5846df576..000000000 --- a/src/routes/(2)guides/(5)testing.mdx +++ /dev/null @@ -1,552 +0,0 @@ ---- -title: Testing -category: Guides -order: 6 -use_cases: >- - testing components, unit tests, integration tests, user interactions, test - coverage, quality assurance -tags: - - testing - - vitest - - components - - unit-tests - - quality -version: "1.0" -description: >- - Test Solid apps with Vitest and Testing Library. Write component tests, - simulate user interactions, and ensure code quality effectively. ---- - -Testing your Solid applications is important to inspiring confidence in your codebase through preventing regressions. - -## Getting started - -### Testing packages explanations - -- [`vitest`](https://vitest.dev) - testing framework that includes runner, assertion engine, and mocking facilities -- [`jsdom`](https://github.com/jsdom/jsdom) - a virtual DOM used to simulate a headless browser environment running in node -- [`@solidjs/testing-library`](https://github.com/solidjs/solid-testing-library/blob/main/README.md) - a library to simplify testing components, directives, and primitives, with automatic cleanup -- [`@testing-library/user-event`](https://testing-library.com/docs/user-event/intro) - used to simulate user events that are closer to reality -- [`@testing-library/jest-dom`](https://testing-library.com/docs/ecosystem-jest-dom) - augments expect with helpful matchers - -### Adding testing packages - -The recommended testing framework for Solid applications is [vitest](https://vitest.dev). - -To get started with vitest, install the following development dependencies: - -```package-install-dev -vitest jsdom @solidjs/testing-library @testing-library/user-event @testing-library/jest-dom -``` - -### Testing configuration - -In your `package.json` add a `test` script calling `vitest`: - -```json title="package.json" - "scripts": { - "test": "vitest" - } -``` - -It is not necessary to add `@testing-library/jest-dom` to the testing options in `vite.config`, since `vite-plugin-solid` automatically detects and loads it if present. - -#### TypeScript configuration - -If using TypeScript, add `@testing-library/jest-dom` to `tsconfig.json#compilerOptions.types`: - -```json title="tsconfig.json" - "compilerOptions": { - // ... - "jsx": "preserve", - "jsxImportSource": "solid-js", - "types": ["vite/client", "@testing-library/jest-dom"] - } -``` - -#### SolidStart configuration - -When using [SolidStart](/solid-start/v2), create a `vitest.config.ts` file: - -```ts title="vitest.config.ts" -import solid from "vite-plugin-solid"; -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - plugins: [solid()], - resolve: { - conditions: ["development", "browser"], - }, -}); -``` - -## Writing tests - -### Components testing - -Testing components involves three main things: - -- Rendering the component -- Interacting with the component -- Validating assertions - -To write tests for your components, create a `[name].test.tsx` file. -The purpose of this file is to describe the intended behavior from a user's perspective in the form of unit tests: - -```jsx tab title="Counter.test.jsx" -import { test, expect } from "vitest"; -import { render } from "@solidjs/testing-library"; -import userEvent from "@testing-library/user-event"; -import { Counter } from "./Counter"; - -const user = userEvent.setup(); - -test("increments value", async () => { - const { getByRole } = render(() => ); - const counter = getByRole("button"); - expect(counter).toHaveTextContent("1"); - await user.click(counter); - expect(counter).toHaveTextContent("2"); -}); -``` - -```jsx tab title="Counter.jsx" -export const Counter = () => { - const [count, setCount] = createSignal(1); - return ; -}; -``` - -In the `test.jsx` file, [the `render` call from `@solidjs/testing-library`](https://testing-library.com/docs/solid-testing-library/api#render) is used to render the component and supply the props and context. -To mimic a user interaction, `@testing-library/user-event` is used. -The [`expect` function provided by `vitest`](https://vitest.dev/api/expect.html) is extended with a [`.toHaveTextContent("content")` matcher from `@testing-library/jest-dom`](https://github.com/testing-library/jest-dom?tab=readme-ov-file#tohavetextcontent) to supply what the expected behavior is for this component. - -To run this test, use the following command: - -```package-run -test -``` - -If running the command is successful, you will get the following result showing whether the tests have passed or failed: - -```ansi frame="none" -[RUN] v1.4.0 solid-app/src/components/Counter.test.tsx - - ✓ src/components/Counter.test.tsx (1) - ✓  (1) - ✓ increments value - - Test Files 1 passed (1) - Tests 1 passed (1) - Start at 16:51:19 - Duration 4.34s (transform 1.01s, setup 205ms, collect 1.54s, tests 155ms, -environment 880ms, prepare 212ms) - -``` - -#### Rendering the component - -The `render` function from `@solidjs/testing-library` creates the testing environment within the `test.tsx` file. -It sets up the container, rendering the component within it, and automatically registers it for clean-up after a successful test. -Additionally, it manages wrapping the component in contexts as well as setting up a router. - -```tsx frame="none" -const renderResult = render( - () => , // @solidjs/testing-library requires a function - { - // all options are optional - container, // manually set up your own container, will not be handled - baseElement, // parent of container in case it is not supplied - queries, // manually set up custom queries - hydrate, // set to `true` to use hydration - wrapper, // reusable wrapper component to supply context - location, // sets up a router pointed to the location if provided - } -); -const { - asFragment, // function returning the contents of the container - baseElement, // the parent of the container - container, // the container in which the component is rendered - debug, // a function giving some helpful debugging output - unmount, // manually removing the component from the container - ...queries // functions to select elements from the container -} = renderResult; -``` - -##### Using the right queries - -Queries are helpers used to find elements within a page. - -``` - ⎧ Role - get ⎫ By ⎪ DisplayValue - query ⎬ ⎨ LabelText - find ⎭ AllBy ⎪ Text - ⎩ ... -``` - -The prefixes (`get`, `query`, and `find`) and the middle portion (`By` and `AllBy`) depend on if the query should wait for an element to appear (or not), whether it should throw an error if the element cannot be found, and how it should handle multiple matches: - -- **getBy**: synchronous, throws if not found or more than 1 matches -- **getAllBy**: synchronous, throws if not found, returns array of matches -- **queryBy**: synchronous, null if not found, error if more than 1 matches -- **queryAllBy**: synchronous, returns array of zero or more matches -- **findBy**: asynchronous, rejected if not found within 1000ms or more than 1 matches, resolves with element if found -- **findAllBy**: asynchronous, rejected if not found within 1000ms, resolves with array of one or more element(s) - -By default, queries should start with `get...`. -If there are multiple elements matching the same query, `getAllBy...` should be used, otherwise use `getBy...`. - -There are two exceptions when you should **not** start with `get...`: - -1. If the `location` option is used or the component is based on resources, the router will be lazy-loaded; in this case, the first query after rendering needs to be `find...` -2. When testing something that is _not_ rendered, you will need to find something that will be rendered at the same time; after that, use `queryAllBy...` to test if the result is an empty array (`[]`). - -The query's suffix (Role, LabelText, ...) depends on the characteristics of the element you want to select. -If possible, try to select for accessible attributes (roughly in the following order): - -- **Role**: [WAI ARIA](https://www.w3.org/WAI/standards-guidelines/aria) landmark roles which are automatically set by semantic elements like `
    - -); -``` - -On the server, tags are collected, and then on the client, server-generated tags are replaced with those rendered on the client side. -This process is important for maintaining the expected behavior, such as Single Page Applications (SPAs) when pages load that require changes to the head tags. - -However, you can manage asset insertion using `getAssets` from `solid-js/web`. diff --git a/src/routes/solid-meta/(0)getting-started/(1)client-setup.mdx b/src/routes/solid-meta/(0)getting-started/(1)client-setup.mdx deleted file mode 100644 index 79065614e..000000000 --- a/src/routes/solid-meta/(0)getting-started/(1)client-setup.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: Client setup -order: 2 -use_cases: >- - seo, meta tags, document head management, social media tags, page titles, - canonical urls -tags: - - meta - - seo - - head - - client - - tags -version: "1.0" -description: >- - Manage document head tags in Solid apps. Add titles, meta tags, and links - dynamically for better SEO and social media sharing. ---- - -You can inject a tag into the `` by rendering one of the head tag components when necessary. -No special requirements are needed on the client side. - -```js -import { MetaProvider, Title, Link, Meta } from "@solidjs/meta"; - -const App = () => ( - -
    - Title of page - - - // ... -
    -
    -); -``` diff --git a/src/routes/solid-meta/(0)getting-started/(2)server-setup.mdx b/src/routes/solid-meta/(0)getting-started/(2)server-setup.mdx deleted file mode 100644 index bd2dd7e09..000000000 --- a/src/routes/solid-meta/(0)getting-started/(2)server-setup.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Server setup -order: 3 -use_cases: >- - ssr setup, server rendering, meta tags on server, seo optimization, initial - page load -tags: - - ssr - - server - - meta - - seo - - setup - - rendering -version: "1.0" -description: >- - Configure server-side rendering for Solid Meta tags with MetaProvider. Learn - to properly inject head tags in SSR for optimal SEO and performance. ---- - -For server setup, wrap your application with [`MetaProvider`](/solid-meta/reference/meta/metaprovider) on the server. -This component uses a `tags[]` array to pass down your head tags as part of your server-rendered payload. -Once rendered on the server, the component updates this array to include the tags. - -```js -import { renderToString, getAssets } from "solid-js/web"; -import { MetaProvider } from "@solidjs/meta"; -import App from "./App"; - -// ... within the context of a request ... -const app = renderToString(() => ( - - - -)); - -res.send(` - - - - ${getAssets()} - - -
    ${app}
    - - -`); -``` diff --git a/src/routes/solid-meta/(0)index.mdx b/src/routes/solid-meta/(0)index.mdx deleted file mode 100644 index 5c07a31d5..000000000 --- a/src/routes/solid-meta/(0)index.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Overview -titleTemplate: ":title" -mainNavExclude: true -use_cases: >- - managing head tags, seo optimization, document metadata, dynamic meta tags, - ssr meta management -tags: - - meta - - head - - seo - - ssr - - overview -version: "1.0" -description: >- - Solid Meta provides asynchronous SSR-ready document head management. Define - meta tags at any component level for flexible SEO and metadata control. ---- - -:::note[Using Solid 2.0?] -This documentation covers `@solidjs/meta` 0.29.x for Solid 1.x. For Solid 2.x, use `@solidjs/meta` 1.x and the [v1 documentation](/solid-meta/v1). -::: - -Solid Meta offers asynchronous SSR-ready Document Head management for Solid Applications, based on [React Head](https://github.com/tizmagik/react-head) - -With Solid Meta, you can define `document.head` tags at any level of your component hierarchy. -This helps you to manage tags conveniently, especially when contextual information for specific tags are buried deep within your component hierarchy. - -This library has no dependencies and is designed to seamlessly integrate with asynchronous rendering. diff --git a/src/routes/solid-meta/reference/meta/base.mdx b/src/routes/solid-meta/reference/meta/base.mdx deleted file mode 100644 index acf5be624..000000000 --- a/src/routes/solid-meta/reference/meta/base.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Base -order: 5 -use_cases: >- - base urls, relative urls, link targets, document head -tags: - - base - - head - - url - - component -version: "1.0" -description: >- - Base renders a base element through Solid Meta. ---- - -`Base` adds a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) element that sets the document base URL for resolving relative URLs. - -## Import - -```tsx -import { Base } from "@solidjs/meta"; -``` - -## Type - -```tsx -const Base: Component>; -``` - -## Props - -Accepts attributes for [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base). - -## Behavior - -- Registers a self-closing `base` tag. -- Non-cascading tags can add one document-head element per active instance. -- Requires [`MetaProvider`](/solid-meta/reference/meta/metaprovider) in the component tree. - -## Examples - -### Basic usage - -```tsx -import { MetaProvider, Base } from "@solidjs/meta"; - -function App() { - return ( - - - - ); -} -``` - -## Related - -- [`MetaProvider`](/solid-meta/reference/meta/metaprovider) -- [`useHead`](/solid-meta/reference/meta/use-head) diff --git a/src/routes/solid-meta/reference/meta/link.mdx b/src/routes/solid-meta/reference/meta/link.mdx deleted file mode 100644 index 8c5119ee5..000000000 --- a/src/routes/solid-meta/reference/meta/link.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: Link -order: 2 -use_cases: >- - links, favicons, stylesheets, preloads, external resources -tags: - - link - - head - - resources - - component -version: "1.0" -description: >- - Link renders a link element through Solid Meta. ---- - -`Link` adds a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) element that defines a relationship between the document and an external resource. - -## Import - -```tsx -import { Link } from "@solidjs/meta"; -``` - -## Type - -```tsx -const Link: Component>; -``` - -## Props - -Accepts attributes for [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link). - -## Behavior - -- Registers a self-closing `link` tag. -- Non-cascading tags can add one document-head element per active instance. -- Requires [`MetaProvider`](/solid-meta/reference/meta/metaprovider) in the component tree. - -## Examples - -### Basic usage - -```tsx -import { MetaProvider, Link } from "@solidjs/meta"; - -function App() { - return ( - - - - ); -} -``` - -## Related - -- [`MetaProvider`](/solid-meta/reference/meta/metaprovider) -- [`useHead`](/solid-meta/reference/meta/use-head) diff --git a/src/routes/solid-meta/reference/meta/meta.mdx b/src/routes/solid-meta/reference/meta/meta.mdx deleted file mode 100644 index c42631930..000000000 --- a/src/routes/solid-meta/reference/meta/meta.mdx +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Meta -order: 3 -use_cases: >- - metadata, descriptions, viewport tags, charset tags, social metadata -tags: - - meta - - head - - metadata - - component -version: "1.0" -description: >- - Meta renders a meta element through Solid Meta. ---- - -`Meta` adds a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta) element for metadata that is not represented by another HTML metadata element. - -## Import - -```tsx -import { Meta } from "@solidjs/meta"; -``` - -## Type - -```tsx -const Meta: Component>; -``` - -## Props - -Accepts attributes for [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta). - -## Behavior - -- Registers a `meta` tag with self-closing server rendering. -- Cascading identity uses `name`, `http-equiv`, `content`, `charset`, `media`, and `property` from the tag props. -- `property` is treated as `name` when Solid Meta builds the tag key. -- Requires [`MetaProvider`](/solid-meta/reference/meta/metaprovider) in the component tree. - -## Examples - -### Basic usage - -```tsx -import { MetaProvider, Meta } from "@solidjs/meta"; - -export default function Root() { - return ( - - - - - - ); -} -``` - -## Related - -- [`MetaProvider`](/solid-meta/reference/meta/metaprovider) -- [`useHead`](/solid-meta/reference/meta/use-head) diff --git a/src/routes/solid-meta/reference/meta/metaprovider.mdx b/src/routes/solid-meta/reference/meta/metaprovider.mdx deleted file mode 100644 index 865947d37..000000000 --- a/src/routes/solid-meta/reference/meta/metaprovider.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: MetaProvider -order: 6 -use_cases: >- - head context, metadata context, document head management -tags: - - provider - - meta - - head - - context - - component -version: "1.0" -description: >- - MetaProvider provides the context used by Solid Meta head tags. ---- - -`MetaProvider` supplies the context that Solid Meta components and [`useHead`](/solid-meta/reference/meta/use-head) use to add head tags. - -## Import - -```tsx -import { MetaProvider } from "@solidjs/meta"; -``` - -## Type - -```tsx -const MetaProvider: ParentComponent; -``` - -## Props - -### `children` - -- **Type:** `JSX.Element` -- **Optional:** Yes - -Content rendered inside the provider. - -## Behavior - -- Creates a `MetaContext.Provider` for its children. -- On the client, active head tags are appended to `document.head` and removed during cleanup. -- During server rendering, rendered head tags are registered through `useAssets`. -- Solid Meta components and [`useHead`](/solid-meta/reference/meta/use-head) throw if they run without a `MetaProvider` in the component tree. - -## Examples - -### Basic usage - -```tsx -import { MetaProvider, Title, Meta } from "@solidjs/meta"; - -export default function Root() { - return ( - - Solid Docs - - - ); -} -``` - -## Related - -- [`Title`](/solid-meta/reference/meta/title) -- [`Meta`](/solid-meta/reference/meta/meta) -- [`Link`](/solid-meta/reference/meta/link) -- [`Style`](/solid-meta/reference/meta/style) -- [`Base`](/solid-meta/reference/meta/base) -- [`useHead`](/solid-meta/reference/meta/use-head) diff --git a/src/routes/solid-meta/reference/meta/style.mdx b/src/routes/solid-meta/reference/meta/style.mdx deleted file mode 100644 index b7d05ff9f..000000000 --- a/src/routes/solid-meta/reference/meta/style.mdx +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: Style -order: 4 -use_cases: >- - style tags, inline css, document head -tags: - - style - - head - - css - - component -version: "1.0" -description: >- - Style renders a style element through Solid Meta. ---- - -`Style` adds a [` - - ); -} -``` - -## Related - -- [`MetaProvider`](/solid-meta/reference/meta/metaprovider) -- [`useHead`](/solid-meta/reference/meta/use-head) diff --git a/src/routes/solid-meta/reference/meta/title.mdx b/src/routes/solid-meta/reference/meta/title.mdx deleted file mode 100644 index 0f197fae0..000000000 --- a/src/routes/solid-meta/reference/meta/title.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Title -order: 1 -use_cases: >- - page titles, document titles, browser tab text, head metadata -tags: - - title - - head - - meta - - component -version: "1.0" -description: >- - Title renders a title element through Solid Meta. ---- - -`Title` adds a [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title) element that sets the document title. - -## Import - -```tsx -import { Title } from "@solidjs/meta"; -``` - -## Type - -```tsx -const Title: Component<JSX.HTMLAttributes<HTMLTitleElement>>; -``` - -## Props - -Accepts attributes for [`<title>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title). - -### `children` - -- **Type:** `JSX.Element` -- **Optional:** Yes - -Content rendered inside the `title` element. - -## Behavior - -- Registers a `title` tag with `close: true` and `escape: true`. -- Cascading keeps the latest active `title` instance in the document head and restores the previous instance when the latest one is removed. -- Requires [`MetaProvider`](/solid-meta/reference/meta/metaprovider) in the component tree. - -## Examples - -### Basic usage - -```tsx -import { MetaProvider, Title } from "@solidjs/meta"; - -export default function Root() { - return ( - <MetaProvider> - <Title>Solid Docs - - ); -} -``` - -## Related - -- [`MetaProvider`](/solid-meta/reference/meta/metaprovider) -- [`useHead`](/solid-meta/reference/meta/use-head) diff --git a/src/routes/solid-meta/reference/meta/use-head.mdx b/src/routes/solid-meta/reference/meta/use-head.mdx deleted file mode 100644 index ed8f062ba..000000000 --- a/src/routes/solid-meta/reference/meta/use-head.mdx +++ /dev/null @@ -1,192 +0,0 @@ ---- -title: useHead -order: 7 -use_cases: >- - custom head tags, scripts, json-ld, arbitrary head elements, head metadata -tags: - - usehead - - head - - meta - - primitive -version: "1.0" -description: >- - useHead adds a custom head tag through Solid Meta. ---- - -`useHead` adds a custom head tag from a `TagDescription` object. - -## Import - -```tsx -import { useHead } from "@solidjs/meta"; -``` - -## Type - -```tsx -type TagDescription = { - tag: string; - props: Record; - setting?: { - close?: boolean; - escape?: boolean; - }; - id: string; - name?: string; - ref?: Element; -}; - -function useHead(tag: TagDescription): void; -``` - -## Parameters - -### Description object - -- **Parameter:** `tag` -- **Type:** `TagDescription` -- **Required:** Yes - -The object passed to `useHead`. - -#### `tag` - -- **Type:** `string` -- **Required:** Yes - -Tag name to render in the document head. - -#### `props` - -- **Type:** `Record` -- **Required:** Yes - -Attributes, properties, and optional `children` applied to the rendered element. - -#### `setting` - -- **Type:** `{ close?: boolean; escape?: boolean }` -- **Required:** No - -Server-rendering options for the tag. - -##### `close` - -- **Type:** `boolean` -- **Required:** No - -When `true`, server rendering emits a closing tag and renders `props.children` between the opening and closing tags. - -##### `escape` - -- **Type:** `boolean` -- **Required:** No - -When `true`, server rendering escapes `props.children`. - -#### `id` - -- **Type:** `string` -- **Required:** Yes - -Identifier used to find server-rendered tags during hydration. - -#### `name` - -- **Type:** `string` -- **Required:** No - -Optional label for the tag description. - -#### `ref` - -- **Type:** `Element` -- **Required:** No - -Existing element reference used by Solid Meta when an element is reused. - -## Return value - -- **Type:** `void` - -`useHead` does not return a value. - -## Behavior - -- Reads `MetaContext` and throws if no [`MetaProvider`](/solid-meta/reference/meta/metaprovider) is present. -- Registers the tag inside a render effect and removes it during cleanup. -- During client rendering, Solid Meta reuses an existing `[data-sm=""]` element when one is present and has the same tag name. -- Server rendering flattens `props.children` arrays into a single string before output. - -## Examples - -### Basic usage - -```tsx -import { createUniqueId } from "solid-js"; -import { MetaProvider, useHead } from "@solidjs/meta"; - -function RssLink() { - useHead({ - tag: "link", - id: createUniqueId(), - props: { - rel: "alternate", - type: "application/rss+xml", - title: "Solid RSS", - href: "/rss.xml", - }, - }); -} - -export default function Root() { - return ( - - - - ); -} -``` - -### Script contents - -```tsx -import { createUniqueId } from "solid-js"; -import { MetaProvider, useHead } from "@solidjs/meta"; - -function JsonLd() { - const jsonLD = JSON.stringify({ - "@context": "https://schema.org", - "@type": "WebSite", - name: "Solid Docs", - url: "https://docs.solidjs.com/", - }); - - useHead({ - tag: "script", - setting: { close: true, escape: false }, - id: createUniqueId(), - props: { - type: "application/ld+json", - children: jsonLD, - }, - }); -} - -export default function Root() { - return ( - - - - ); -} -``` - -## Related - -- [`MetaProvider`](/solid-meta/reference/meta/metaprovider) -- [`Title`](/solid-meta/reference/meta/title) -- [`Meta`](/solid-meta/reference/meta/meta) -- [`Link`](/solid-meta/reference/meta/link) -- [`Style`](/solid-meta/reference/meta/style) -- [`Base`](/solid-meta/reference/meta/base) diff --git a/src/routes/solid-meta/v1/(0)index.mdx b/src/routes/solid-meta/v1/(0)index.mdx deleted file mode 100644 index 4af8ee04f..000000000 --- a/src/routes/solid-meta/v1/(0)index.mdx +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Overview -titleTemplate: ":title" -mainNavExclude: true -use_cases: >- - managing head tags, seo optimization, document metadata, dynamic meta tags, - ssr meta management, streaming head updates -tags: - - meta - - head - - seo - - ssr - - overview -version: "1.0" -description: >- - Solid Meta 1.0 provides document head management for Solid 2.0 — declare - head tags anywhere with streaming-correct SSR and flicker-free hydration. ---- - -:::note[Solid Meta 1.0 is for Solid 2.0] -Solid Meta 1.x requires Solid 2.x (currently in beta). If you are using Solid 1.x, use `@solidjs/meta` 0.29.x and the [latest documentation](/solid-meta) instead. -::: - -Solid Meta provides document head management for Solid applications — declare ``, `<meta>`, `<link>`, and other head elements anywhere in your component tree, with streaming-correct server rendering and flicker-free hydration. - -Solid Meta 1.x is a thin component layer over Solid 2.0's built-in head registry (`useHead` in `@solidjs/web`). There is **no provider** — the registry is ambient. Render a head component anywhere and it registers under the current reactive owner, and server rendering splices the winning tags into your document automatically. - -| Solid version | @solidjs/meta version | -| ------------- | --------------------- | -| Solid 2.x | 1.x | -| Solid 1.x | 0.27.x – 0.29.x | -| Solid 0.x | 0.26.x | - -If you are upgrading an existing app from `@solidjs/meta` 0.x, start with the [migration guide](/solid-meta/v1/migrating-from-v0). diff --git a/src/routes/solid-router/(0)getting-started/(0)installation-and-setup.mdx b/src/routes/solid-router/(0)getting-started/(0)installation-and-setup.mdx deleted file mode 100644 index 782cf3dbc..000000000 --- a/src/routes/solid-router/(0)getting-started/(0)installation-and-setup.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Installation and setup -use_cases: >- - starting new project, initial setup, configuring routing, spa applications, - client-side routing -tags: - - setup - - installation - - configuration - - spa - - routing - - getting-started -version: "1.0" -description: >- - Learn how to install and configure Solid Router for client and server-side - routing in your single-page applications with step-by-step setup guide. ---- - -Solid Router is the universal router for Solid which works for rendering on the client or the server. -It was inspired by and combines paradigms of [React Router](https://reactrouter.com/en/main) and the [Ember Router](https://guides.emberjs.com/release/routing/). - -A router provides a way to change a user's view based on the URL in the browser. -This allows a "single-page" application to simulate a traditional multipage site. -To use Solid Router, components called Routes that depend on the value of the URL (the "path") are specified, and the router handles the mechanism of swapping them in and out. - -## Setup - -To get started with Solid Router, install it using your preferred package manager. - -```package-install -@solidjs/router -``` - -## Configure the routes - -The [`Router`](/solid-router/reference/components/router) component is the root component of the router. -It is responsible for managing the URL and rendering the appropriate [`Route`](/solid-router/reference/components/route) based on the URL. - -To configure your routes, import the `Router` component and then start the application by rendering the router component. - -```jsx -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -const wrapper = document.getElementById("app"); - -if (!wrapper) { - throw new Error("Wrapper div not found"); -} - -render(() => <Router />, wrapper); -``` - -This sets up the router that will match on the url and render the appropriate route. diff --git a/src/routes/solid-router/(0)getting-started/(1)component.mdx b/src/routes/solid-router/(0)getting-started/(1)component.mdx deleted file mode 100644 index d26965595..000000000 --- a/src/routes/solid-router/(0)getting-started/(1)component.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Component routing -use_cases: >- - defining routes, jsx routing, template-based routing, initial setup, basic - navigation -tags: - - jsx - - components - - routing - - setup - - templates -version: "1.0" -description: >- - Define routes using JSX components in SolidJS Router for intuitive, - template-based routing in your applications. ---- - -In Solid Router, routes can be defined directly in an application's template using JSX. -This is the most common way to define routes in Solid Router. - -To define routes using JSX, the [`Route`](/solid-router/reference/components/route) is added to the [`<Router>`](/solid-router/reference/components/router) component for each path you want to define: - -```jsx -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -import Home from "./routes/Home"; - -render( - () => ( - <Router> - <Route path="/" component={Home} /> - </Router> - ), - document.getElementById("app") -); -``` - -The Route component takes a `path` prop, which is the path to match, and a `component` prop, where you pass the component (or element) to render when the path matches. -In the example above, the `Home` page is rendered when the user navigates to the root path `/`. - -To apply multiple routes to the router, add additional `Route` components to the `Router`: - -```jsx -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -import Home from "./routes/index.jsx"; -import About from "./routes/about.jsx"; - -render( - () => ( - <Router> - <Route path="/" component={Home} /> - <Route path="/hello-world" component={() => <h1>Hello World!</h1>} /> - <Route path="/about" component={About} /> - </Router> - ), - document.getElementById("app") -); -``` - -This example defines three routes: the root path (`/`) which renders the `Home` page, the path `/hello-world` which renders an `h1` element, and the path `/about` which renders the `About` component. diff --git a/src/routes/solid-router/(0)getting-started/(2)config.mdx b/src/routes/solid-router/(0)getting-started/(2)config.mdx deleted file mode 100644 index 8b3c66eb0..000000000 --- a/src/routes/solid-router/(0)getting-started/(2)config.mdx +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Config-based routing -use_cases: >- - centralized routing, lazy loading, config-based setup, dynamic imports, - performance optimization -tags: - - config - - lazy-loading - - routing - - performance - - setup -version: "1.0" -description: >- - Configure SolidJS routes with config objects for centralized routing, lazy - loading, and optimized performance. ---- - -Solid Router supports config-based routing, which offers the same capabilities as [component routing](/solid-router/getting-started/component). -The decision to use config-based routing over component routing depends largely on personal preference. - -To define a single route, a route definition object can be passed to the [`<Router>`](/solid-router/reference/components/router) component: - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -const routes = { - path: "/", - component: lazy(() => import("/routes/index.js")), -}; - -render(() => <Router>{routes}</Router>, document.getElementById("app")); -``` - -In the route definition object, a `path` property must be provided to define the path to match and a `component` property that specifies the component (or element) to render when the path matches. - -To define multiple routes, an array of route definition objects can be passed to the `<Router>` component: - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -const routes = [ - { - path: "/", - component: lazy(() => import("/routes/index.js")), - }, - { - path: "/hello-world", - component: () => <h1>Hello, World!</h1>, - }, - { - path: "/about", - component: lazy(() => import("/routes/about.js")), - }, -]; - -render(() => <Router>{routes}</Router>, document.getElementById("app")); -``` - -Each path in the array of route definition objects will be matched against the current URL, and the corresponding component will be rendered when a match is found. -In the example above, the root path (`/`) renders the `Home` page, the path `/hello-world` renders an `h1` element, and the path `/about` renders the `About` component. - -:::note[Lazy Loading] -When using configuration-based routing, it is best practice to use the [`lazy`](/reference/component-apis/lazy) component to load components asynchronously. -This will help improve the performance of your application by only loading the components when they are needed. - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -const routes = [ - { - path: "/", - component: lazy(() => import("/routes/index.js")), - }, - { - path: "/hello-world", - component: () => <h1>Hello, World!</h1>, - }, - { - path: "/about", - component: lazy(() => import("/routes/about.js")), - }, -]; - -render(() => <Router>{routes}</Router>, document.getElementById("app")); -``` - -To learn more about lazy loading, see the page on [lazy loading components](/solid-router/advanced-concepts/lazy-loading). -::: diff --git a/src/routes/solid-router/(0)getting-started/(3)linking-routes.mdx b/src/routes/solid-router/(0)getting-started/(3)linking-routes.mdx deleted file mode 100644 index 52ea8428d..000000000 --- a/src/routes/solid-router/(0)getting-started/(3)linking-routes.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: Linking routes -use_cases: >- - navigation between pages, creating menu bars, active link styling, internal - linking, user navigation -tags: - - navigation - - links - - anchors - - active-states - - menu - - ui -version: "1.0" -description: >- - Create navigation links between routes using anchor tags and the A component - with active state styling and automatic base path handling. ---- - -Once routes have been created within an application, using anchor tags will help users navigate between different views or pages. - -```jsx {4-5} -const App = (props) => ( - <> - <nav> - <a href="/users">Users</a> - <a href="/">Home</a> - </nav> - <h1>My Site with lots of pages</h1> - {props.children} - </> -); - -render( - () => ( - <Router root={App}> - <Route path="/users" component={Users} /> - <Route path="/" component={Home} /> - </Router> - ), - document.getElementById("app") -); -``` - -## `<A>` component - -Solid Router also offers an [`<A>`](/solid-router/reference/components/a) component. -The `<A>` component is similar to the HTML anchor tag but supports automatically applying the base URL path and relative paths. - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route, A } from "@solidjs/router"; - -const Users = lazy(() => import("./pages/Users")); -const Home = lazy(() => import("./pages/Home")); - -const App = (props) => ( - <> - <nav> - <A href="/users">Users</A> - <A href="/">Home</A> - </nav> - <h1>My Site with lots of pages</h1> - {props.children} - </> -); - -render( - () => ( - <Router root={App}> - <Route path="/users" component={Users} /> - <Route path="/" component={Home} /> - </Router> - ), - document.getElementById("app") -); -``` - -In addition, the `<A>` component has an `active` class if its `href` matches the current location, and `inactive` otherwise. -This provides the link with a CSS class to show when the link is active or inactive. - -```jsx -<A href="/users" activeClass="underlined" inactiveClass="default"> - Users -</A> -``` - -By default, matching using the `<A>` component includes locations that are _descendants_ (eg. `/users` and `/users/123`). -This component offers the `end` prop, which takes in a boolean to prevent matching these. -This can be useful when links to the root route (`/`) would match everything. diff --git a/src/routes/solid-router/(0)index.mdx b/src/routes/solid-router/(0)index.mdx deleted file mode 100644 index 14b63b334..000000000 --- a/src/routes/solid-router/(0)index.mdx +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Overview -titleTemplate: ":title" -use_cases: >- - understanding routing, learning basics, overview needed, getting started, spa - routing concepts -tags: - - overview - - introduction - - basics - - spa - - routing - - concepts -version: "1.0" -description: >- - Solid Router is the universal routing solution for Solid applications, - enabling client and server-side navigation in single-page applications. ---- - -:::note[Prerequisites] -The docs are based on latest Solid Router. -To use this version, you need to have Solid v1.8.4 or later installed. -::: - -Solid Router is the universal router for Solid which works for rendering on the client or the server. -It was inspired by and combines paradigms of [React Router](https://reactrouter.com/en/main) and the [Ember Router](https://guides.emberjs.com/release/routing/). - -A router provides a way to change a user's view based on the URL in the browser. -This allows a "single-page" application to simulate a traditional multipage site. -To use Solid Router, components called Routes that depend on the value of the URL (the "path") are specified, and the router handles the mechanism of swapping them in and out. diff --git a/src/routes/solid-router/(1)concepts/(0)navigation.mdx b/src/routes/solid-router/(1)concepts/(0)navigation.mdx deleted file mode 100644 index 82a21ae3c..000000000 --- a/src/routes/solid-router/(1)concepts/(0)navigation.mdx +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: Navigation -use_cases: >- - page transitions, programmatic routing, user actions, form submissions, - authentication flows, redirects -tags: - - navigation - - links - - redirects - - routing - - programmatic -version: "1.0" -description: >- - Navigate between routes in SolidJS using links, programmatic navigation, and - redirects for seamless user experiences. ---- - -When using Solid Router, you can use the standard standard HTML [`<a>` elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a), which triggers [soft navigation](/solid-router/reference/components/a#soft-navigation). -In addition to using this, Solid Router offers other options for navigating between routes: - -- The [`<A>` component](/solid-router/reference/components/a). -- The [`useNavigate` primitive](/solid-router/reference/primitives/use-navigate). -- The [`redirect` function](/solid-router/reference/response-helpers/redirect). - -## `<A>` component - -The `<A>` component extends the native `<a>` element by automatically applying the base URL path and, additionally, supports relative paths. - -```tsx -import { A } from "@solidjs/router"; - -function DashboardPage() { - return ( - <main> - <nav> - <A href="/">Home</A> - </nav> - {/* This is a relative path that, from /dashboard, links to /dashboard/users */} - <A href="users">Users</A> - </main> - ); -} -``` - -See the [`<A>` API reference](/solid-router/reference/components/a) for more information. - -### Styling - -The `<A>` component allows you to style links based on their active state using the `activeClass` and `inactiveClass` props. -When provided, these props apply the corresponding CSS classes to the link. -If omitted, the default classes `active` and `inactive` are used. - -By default, a link is considered active when the current route matches the link's `href` or any of its descendant routes. -For example, a link with `href="/dashboard"` is active when the current route is `/dashboard`, `/dashboard/users`, or `/dashboard/users/1/profile`. - -To match an exact route, the prop `end` can be used. -When `true`, it ensures that the link is only considered active if the `href` exactly matches the current route. -This is useful for root route links (href="/"), which might otherwise match all routes. - -```tsx -import { A } from "@solidjs/router"; - -function Navbar() { - return ( - <nav> - <A href="/" end={true}> - Home - </A> - <A - href="/login" - activeClass="text-blue-900" - inactiveClass="text-blue-500" - > - Login - </A> - </nav> - ); -} -``` - -## `useNavigate` primitive - -The `useNavigate` primitive allows for programmatically navigating to a specified route. - -```tsx -import { useNavigate } from "@solidjs/router"; - -function LoginPage() { - const navigate = useNavigate(); - - return ( - <button - onClick={() => { - // Login logic - navigate("/dashboard", { replace: true }); - }} - > - Login - </button> - ); -} -``` - -This example redirects the user to `/dashboard` after login. -By using `replace: true`, the login page is removed from the browser's history stack and replaced with the `/dashboard` route. -This prevents the user from navigating back to the login page using the back button. - -See the [`useNavigate` API reference](/solid-router/reference/primitives/use-navigate) for more information. - -## `redirect` function - -The `redirect` function returns a [`Response` object](https://developer.mozilla.org/en-US/docs/Web/API/Response), which enables navigation to a specified route within [query](/solid-router/reference/data-apis/query) or [action](/solid-router/reference/data-apis/action). - -```tsx -import { action, redirect } from "@solidjs/router"; - -const logout = action(async () => { - localStorage.remove("token"); - throw redirect("/"); -}); -``` - -See the [`redirect` API reference](/solid-router/reference/response-helpers/redirect) for more information. diff --git a/src/routes/solid-router/(1)concepts/(1)path-parameters.mdx b/src/routes/solid-router/(1)concepts/(1)path-parameters.mdx deleted file mode 100644 index 1b7ef9829..000000000 --- a/src/routes/solid-router/(1)concepts/(1)path-parameters.mdx +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Path parameters -use_cases: >- - dynamic content, user profiles, resource ids, filtering data, validation, - flexible routing -tags: - - parameters - - validation - - dynamic - - wildcards - - routing -version: "1.0" -description: >- - Capture and validate dynamic URL parameters in SolidJS routes for flexible - content display and data-driven pages. ---- - -Parameters within a route are used to capture dynamic values from the URL. -This is useful for creating routes that are more flexible and can handle different values. - -```jsx -<Route path="/users/:id" component={User} /> -``` - -In this example, the `:id` parameter will capture any value that comes after `/users/` in the URL. -The colon `:` is used to denote a parameter, and `id` is the name of the parameter. -When a URL matches this route, the `User` component will be rendered. - -:::note[Animations & Transitions] -Routes that share the same path match will be treated as the same route. -If a force re-render is needed, you can wrap your component in a keyed [`Show`](/reference/components/show) component: - -```jsx -<Show when={params.something} keyed> - <MyComponent /> -</Show> -``` - -::: - -## Accessing parameters - -You can retrieve the values captured by parameters using [`useParams`](/solid-router/reference/primitives/use-params). - -```jsx frame="terminal" title="http://localhost:3000/users/123" -import { useParams } from "@solidjs/router"; - -function User() { - const params = useParams(); - return <div>User ID: {params.id}</div>; - { - /* Output: User ID: 123 */ - } -} -``` - -## Validating parameters - -Each path parameter can be validated using the `MatchFilter` on the `Route` component. -Rather than checking for the presence of a parameter manually, you can use a `MatchFilter` to ensure that the parameter is in the correct format. - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -const User = import("./pages/User"); - -const filters = { - parent: ["mom", "dad"], // allow enum values - id: /^\d+$/, // only allow numbers - withHtmlExtension: (v: string) => v.length > 5 && v.endsWith(".html"), // we want an `*.html` extension -}; - -render(() => ( - <Router> - <Route - path="/users/:parent/:id/:withHtmlExtension" - component={User} - matchFilters={filters} - /> - </Router> -), document.getElementById("app")); - -``` - -Here, the `matchFilter` prop validates the `parent`, `id`, and `withHtmlExtension` parameters against the specified filters defined in the `filters` object. -If the validation fails, the route will not match and the component will not be rendered. - -In this example, that means: - -- `/users/mom/123/contact.html` would match, -- `/users/dad/456/about.html` would match, -- `/users/aunt/123/contact.html` would not match as `:parent` is not 'mom' or 'dad', -- `/users/mom/me/contact.html` would not match as `:id` is not a number, -- `/users/dad/123/contact` would not match as `:withHtmlExtension` is missing .html. - -## Optional parameters - -Parameters can be made optional by adding a `?` after the parameter name. - -```jsx -<Route path="/users/:id?" component={User} /> -``` - -With this setup, the route would match both `/users` and `/users/123`. -However, it is important to note that the `?` only makes the parameter optional for the last segment of the path. -As a result, paths beyond the optional parameter will _not_ be matched. -For instance, `/users/123/contact` would not match. - -## Wildcard routes - -Wildcard routes can be used to match any number of segments in a path. -To create a wildcard route, use `*` followed by the parameter name. - -```jsx -<Route path="/users/*" component={User} /> -``` - -Using an asterisk `*` as a parameter will match any number of segments after `/users`. -This includes `/users`, `/users/123`, `/users/123/contact`, and so on. - -If you need to expose the wildcard segments of the path, you can name them: - -```jsx -<Route path="/users/*rest" component={User} /> -``` - -In this case, `rest` will contain the rest of the path after `/users/`. - -It is important to note that wildcard routes must be located at the **end of the path**. -If you place a wildcard route before the end, such as `/users/*rest/:id`, no routes will be matched. diff --git a/src/routes/solid-router/(1)concepts/(2)search-parameters.mdx b/src/routes/solid-router/(1)concepts/(2)search-parameters.mdx deleted file mode 100644 index 98cd76e7d..000000000 --- a/src/routes/solid-router/(1)concepts/(2)search-parameters.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: Search parameters -use_cases: >- - filtering, pagination, search queries, form state in url, shareable urls, - stateful navigation -tags: - - query-params - - search - - state - - url - - routing -version: "1.0" -description: >- - Manage query strings and search parameters in SolidJS for filtering, - pagination, and maintaining state in the URL. ---- - -Search parameters are used to pass data to a route using the query string. -The query string is the part of the URL that comes after the `?` character and is used to pass key-value pairs to the route. - -In Solid Router, these query parameters can be accessed using [`useSearchParams`](/solid-router/reference/primitives/use-search-params). -This primitive retrieves a tuple that contains a reactive object that reads the current search parameters and a function to update them. - -```jsx {4} -import { useSearchParams } from "@solidjs/router"; - -export const App = () => { - const [searchParams, setSearchParams] = useSearchParams(); - - return ( - <div> - <span>Username: {searchParams.username}</span> - <input - type="text" - onChange={(e) => { - e.preventDefault(); - setSearchParams({ username: e.target.value }); - }} - /> - </div> - ); -}; -``` - -The getter, in this case `searchParams`, is used to read the current search parameters. -`setSearchParams` works as the setter which accepts an _object_ whose entries will be merged into the current query. - -## Multiple queries - -Since `setSearchParams` accepts an object, you can pass multiple key-value pairs to update multiple search parameters at once. - -```jsx -setSearchParams({ - username: "john", - page: 1, -}); -``` - -:::note[Empty or null values] -If the value of a search parameter's key is `undefined`, `null`, or an empty -string (`""`), it will be removed from the query string. -::: - -## Accessing query strings - -If you require accessing the query string directly, you can use the [`useLocation`](/solid-router/reference/primitives/use-location) primitive: - -```jsx -import { useLocation } from "@solidjs/router"; - -export const App = () => { - const location = useLocation(); - - return ( - <div> - <span>Query String: {location.search}</span> - </div> - ); -}; -``` - -If the URL was `http://localhost:3000/users?username=john&page=1`, the output would be `Query String: ?username=john&page=1`. diff --git a/src/routes/solid-router/(1)concepts/(3)catch-all.mdx b/src/routes/solid-router/(1)concepts/(3)catch-all.mdx deleted file mode 100644 index c2668856b..000000000 --- a/src/routes/solid-router/(1)concepts/(3)catch-all.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Catch-all routes -use_cases: >- - 404 pages, handling invalid urls, fallback routes, error boundaries, redirect - unknown paths -tags: - - "404" - - error-pages - - fallback - - routing - - wildcards -version: "1.0" -description: >- - Create catch-all routes in SolidJS to handle 404 errors and redirect users - from invalid URLs to proper fallback pages. ---- - -Catch-all routes are used to match any URL that does not match any other route in the application. -This is useful for displaying a 404 page or redirecting to a specific route when a user enters an invalid URL. - -To create a catch-all route, place a route with an asterisk (`*`) as the path at the end of the route list. -Optionally, you can name the parameter to access the unmatched part of the URL. - -```jsx -import { Router, Route } from "@solidjs/router"; - -import Home from "./Home"; -import About from "./About"; -import NotFound from "./NotFound"; - -const App = () => ( - <Router> - <Route path="/home" component={Home} /> - <Route path="/about" component={About} /> - <Route path="*404" component={NotFound} /> - </Router> -); -``` - -Now, if a user navigates to a URL that does not match `/home` or `/about`, the `NotFound` component will be rendered. diff --git a/src/routes/solid-router/(1)concepts/(4)dynamic-routes.mdx b/src/routes/solid-router/(1)concepts/(4)dynamic-routes.mdx deleted file mode 100644 index 9be0e08de..000000000 --- a/src/routes/solid-router/(1)concepts/(4)dynamic-routes.mdx +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: Dynamic routes -use_cases: >- - user profiles, product pages, blog posts, id-based content, variable urls, - data-driven pages -tags: - - dynamic - - parameters - - validation - - wildcards - - routing -version: "1.0" -description: >- - Build dynamic routes with parameters in SolidJS for user profiles, products, - and content that changes based on URL values. ---- - -When a path is unknown ahead of time, it can be treated as a flexible parameter that is passed on to the component: - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -const Users = lazy(() => import("./pages/Users")); -const User = lazy(() => import("./pages/User")); -const Home = lazy(() => import("./pages/Home")); - -render( - () => ( - <Router> - <Route path="/users" component={Users} /> - <Route path="/users/:id" component={User} /> - <Route path="/" component={Home} /> - </Router> - ), - document.getElementById("app") -); -``` - -The colon (`:`) indicates that `id` can be any string. -Once a URL matches the pattern, the `User` component will be shown. -When using dynamic segments, the values can be accessed via the [`useParams`](/solid-router/reference/primitives/use-params) primitive within the component. - -:::note[Note on Animation/Transitions] -Routes that share the same path match will be treated as the same route. -If you want to force re-render you can wrap your component in a keyed [`Show`](/concepts/control-flow/conditional-rendering) like: - -```jsx -<Show when={params.something} keyed> - <MyComponent /> -</Show> -``` - -::: - -Each path parameter can be validated using a `MatchFilter`. -This allows for more complex routing descriptions rather than just checking the presence of a parameter. - -```jsx -import { lazy } from "solid-js"; -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; -import type { SegmentValidators } from "./types"; - -const User = lazy(() => import("./pages/User")); - -const filters: MatchFilters = { - parent: ["mom", "dad"], // allow enum values - id: /^\d+$/, // only allow numbers - withHtmlExtension: (v: string) => v.length > 5 && v.endsWith(".html"), // we want an `*.html` extension -}; - -render( - () => ( - <Router> - <Route - path="/users/:parent/:id/:withHtmlExtension" - component={User} - matchFilters={filters} - /> - </Router> - ), - document.getElementById("app") -); - -``` - -Here, `matchFilters` prop allows for validation of the `parent`, `id` and `withHtmlExtension` parameters against the filters defined in `filters`. -If the validation fails, the route will not match. - -So in this example: - -- `/users/mom/123/contact.html` would match, -- `/users/dad/123/about.html` would match, -- `/users/aunt/123/contact.html` would not match as `:parent` is not 'mom' or 'dad', -- `/users/mom/me/contact.html` would not match as `:id` is not a number, -- `/users/dad/123/contact` would not match as `:withHtmlExtension` is missing `.html`. - -## Optional parameters - -Parameters can be specified as optional by adding a question mark to the end of the parameter name: - -```jsx -// Matches stories and stories/123 but not stories/123/comments -<Route path="/stories/:id?" component={Stories} /> -``` - -## Wildcard routes - -`:param` provides an arbitrary name at that point in the path. -Using an asterisk (`*`) will provide a way to match any end of the path: - -```jsx -// Matches any path that begins with foo, including foo/, foo/a/, foo/a/b/c -<Route path="foo/*" component={Foo} /> -``` - -If the wild part of the path to the component as a parameter needs to be exposed, it can be named: - -```jsx -<Route path="foo/*any" component={Foo} /> -``` - -**Note:** that the wildcard token must be the last part of the path; `foo/*any/bar` will not create any routes. - -## Multiple paths - -Routes also support defining multiple paths using an array. -This allows a route to remain mounted and not rerender when switching between two or more locations that it matches: - -```jsx -// Navigating from login to register does not cause the Login component to re-render -<Route path={["login", "register"]} component={Login} /> -``` diff --git a/src/routes/solid-router/(1)concepts/(5)nesting.mdx b/src/routes/solid-router/(1)concepts/(5)nesting.mdx deleted file mode 100644 index 44616c0e4..000000000 --- a/src/routes/solid-router/(1)concepts/(5)nesting.mdx +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: Nesting routes -use_cases: >- - hierarchical pages, parent-child relationships, shared layouts, complex - routing structures, admin sections -tags: - - nesting - - hierarchy - - routing - - layouts - - config -version: "1.0" -description: >- - Build nested route hierarchies in SolidJS for complex applications with - parent-child relationships and shared layouts. ---- - -Nested routes are a way to create a hierarchy of routes in your application. -This is useful for creating a [layout](/solid-router/concepts/layouts) that is consistent across multiple pages, or for creating a relationship between pages that are related to each other. - -In Solid Router, the following two route definitions have the same result: - -```jsx -<Route path="/users/:id" component={User} /> - -// is equivalent to - -<Route path="/users"> - <Route path="/:id" component={User} /> -</Route> -``` - -In both cases, the `User` component will render when the URL is `/users/:id`. -The difference, however, is that in the first case, `/users/:id` is the only route, and in the second case, `/users` is also a route. - -**Note:** visit the [config-based nesting](#config-based-nesting) section for more information on how to nest routes using the configuration-based approach. - -## Limitations - -When nesting routes, only the innermost `Route` component will become its own route. -For example, if you were to nest a route, only the innermost route will become its own route, even if the parent routes are also specified and provided with a component: - -```jsx -<Route path="/users" component={Users}> - <Route path="/:id" component={User} /> -</Route> -``` - -For a parent route to become its own route, it must be specified separately. This can be done by explicitly defining the parent route as well as the nested route: - -```jsx -<Route path="/users" component={Users} /> -<Route path="/users/:id" component={User} /> -``` - -Another way to achieve the same result is to nest the routes and explicitly define the parent route through the use of an empty path, and then specify the nested route: - -```jsx -<Route path="/users"> - <Route path="/" component={Users} /> - <Route path="/:id" component={User} /> -</Route> -``` - -In both cases, the `Users` component will render when the URL is `/users`, and the `User` component will render when the URL is `/users/:id`. - -## Config-based nesting - -When using configuration-based routing, nesting can be achieved through passing your route definitions into the `children` property of a parent route definition object: - -```jsx -import { render } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -const routes = { - path: "/", - component: lazy(() => import("/routes/index.js")), - children: [ - { - path: "/users", - component: lazy(() => import("/routes/users.js")), - children: [ - { - path: "/:id", - component: lazy(() => import("/routes/user.js")), - }, - ], - }, - ], -}; - -render(() => <Router>{routes}</Router>, document.getElementById("app")); -``` - -In this example, when you navigate to `/users/:id`, the `User` component will render. -Similarly, when you navigate to `/users`, the `Users` component will render. diff --git a/src/routes/solid-router/(1)concepts/(6)layouts.mdx b/src/routes/solid-router/(1)concepts/(6)layouts.mdx deleted file mode 100644 index 0ae860298..000000000 --- a/src/routes/solid-router/(1)concepts/(6)layouts.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: Layouts -use_cases: >- - consistent headers/footers, shared navigation, admin panels, dashboard - layouts, nested ui structure -tags: - - layouts - - nesting - - ui-structure - - components - - routing -version: "1.0" -description: >- - Create consistent page layouts in SolidJS with shared headers, footers, and - nested structures for better UI organization. ---- - -To maintain consistency across an application's page you can use layouts. -Layouts are components that wrap the content of a route and can be used to define a common structure for all pages or specific sections of an application. - -## Root-level layouts - -A root-level layout acts as a container surrounding all routes within your application. -To define a root-level layout, pass the layout component to the `root` prop of the `Router` component: - -```jsx -import { render } from "solid-js/web"; -import { Router, Route } from "@solidjs/router"; - -import Home from "./pages/Home"; - -const Layout = (props) => { - return ( - <> - <header>Header</header> - {props.children} - <footer>Footer</footer> - </> - ); -}; - -render( - () => ( - <Router root={Layout}> - <Route path="/" component={Home} /> - <Route path="/hello-world" component={() => <div>Hello world!</div>} /> - </Router> - ), - document.getElementById("app") -); -``` - -With the root-level layout, `props.children` will be replaced with the content of the current route. -This means that while the words "Header" and "Footer" will be displayed on every page, the content between them will change depending on the current route. -For example, when the route is `/hello-world`, you will see the text "Hello world!" between the header and footer. - -## Nested layouts - -When you want to create a layout that is specific to a group of routes, you can nest routes within a layout component. -This can be done by passing `props.children` to the component where the nested routes are defined: - -```jsx -function PageWrapper(props) { - return ( - <div> - <h1> We love our users! </h1> - {props.children} - <A href="/">Back Home</A> - </div> - ); -} -``` - -While the routes are still configured the same, the route's elements will appear inside the parent element where the `props.children` was declared. -For `PageWrapper` to be used as a layout, in this case, you can pass it as a component to the parent route: - -```jsx -<Router> - <Route path="/users" component={PageWrapper}> - <Route path="/" component={Users} /> - <Route path="/:id" component={User} /> - </Route> -</Router> -``` - -Now, when the route is `/users`, the content of the `Users` component will be displayed inside the `PageWrapper` component. -Similarly, when navigating to `/users/1`, the content of the `User` component will be displayed inside the `PageWrapper` component as well. diff --git a/src/routes/solid-router/(1)concepts/(7)alternative-routers.mdx b/src/routes/solid-router/(1)concepts/(7)alternative-routers.mdx deleted file mode 100644 index 71a2f7698..000000000 --- a/src/routes/solid-router/(1)concepts/(7)alternative-routers.mdx +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Alternative routers -use_cases: >- - single-page apps without server routing, legacy hash-based urls, testing - router logic, client-only navigation -tags: - - hash-mode - - memory-mode - - client-side - - testing - - spa - - routing -version: "1.0" -description: >- - Learn to use hash-based and memory routers in SolidJS for client-side - navigation and testing without server interaction. ---- - -While the default router uses the browser's `location.pathname` to determine the current route, you can use alternative routers to change this behavior. -This includes: - -- [**Hash mode**](#hash-mode): Uses the hash portion of the URL to determine the current route. -- [**Memory mode**](#memory-mode): Keeps the history of the router in memory, useful for testing. - -## Hash mode - -Hash mode routing uses the hash portion of the URL to manage an application's state and navigation. -Unlike the [default router](/solid-router/reference/components/router), the hash portion of the URL will not be handled by the server, meaning this is a client-side only routing. -To use hash mode, replace the `<Router />` component in the application with [`<HashRouter />`](/solid-router/reference/components/hash-router). - -```jsx del={3, 16} ins={4,17} -import { render } from "solid-js/web"; -import { - Router - HashRouter, - Route - } from "@solidjs/router"; - -const App = (props) => ( - <> - <h1>Root header</h1> - {props.children} - </> -); - -render( - () => <Router root={App}>{/*... routes */}</Router>, - () => <HashRouter root={App}>{/*... routes */}</HashRouter>, - document.getElementById("app") -); - -``` - -## Memory mode - -Unlike the default router and hash, the memory router does not interact with the browser's URL. -This means that while the URL in the browser's address bar will change, the router will not navigate to the new route. -This gives you the ability to control the router's state and history in memory which can be useful for testing purposes. - -To use memory mode, replace the `<Router />` component in the application with [`<MemoryRouter />`](/solid-router/reference/components/memory-router): - -```jsx del={3, 16} ins={4,17} -import { render } from "solid-js/web"; -import { - Router - MemoryRouter, - Route - } from "@solidjs/router"; - -const App = (props) => ( - <> - <h1>Root header</h1> - {props.children} - </> -); - -render( - () => <Router root={App}>{/*... routes */}</Router>, - () => <MemoryRouter root={App}>{/*... routes */}</MemoryRouter>, - document.getElementById("app") -); - -``` diff --git a/src/routes/solid-router/(1)concepts/(8)actions.mdx b/src/routes/solid-router/(1)concepts/(8)actions.mdx deleted file mode 100644 index 6c76f04cf..000000000 --- a/src/routes/solid-router/(1)concepts/(8)actions.mdx +++ /dev/null @@ -1,461 +0,0 @@ ---- -title: Actions -use_cases: >- - form submissions, data mutations, server communication, user input handling, - api calls, crud operations -tags: - - actions - - forms - - data - - api - - server - - submission - - mutations -version: "1.0" -description: >- - Handle form submissions and server mutations with Solid Router actions. Build - isomorphic data flows with progressive enhancement support. ---- - -Many user interactions in an application involve changing data on the server. -These **mutations** can be challenging to manage, as they require updates to the application's state and proper error handling. -Actions simplify managing data mutations. - -Actions provide several benefits: - -- **Integrated state management:** - Solid Router automatically tracks the execution state of an action, simplifying reactive UI feedback. -- **Automatic data revalidation:** - After an action successfully completes, Solid Router revalidates relevant [`queries`](/solid-router/data-fetching/queries), ensuring the UI reflects the latest data. -- **Progressive enhancement:** - When used with HTML forms, actions enable functionality even if JavaScript is not yet loaded. - -## Defining actions - -Actions are defined by wrapping the data-mutation logic with the [`action` function](/solid-router/reference/data-apis/action). - -```tsx -import { action } from "@solidjs/router"; - -const createTicketAction = action(async (subject: string) => { - const response = await fetch("https://my-api.com/support/tickets", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ subject }), - }); - - if (!response.ok) { - const errorData = await response.json(); - return { ok: false, message: errorData.message }; - } - - return { ok: true }; -}, "createTicket"); -``` - -In this example, an action is defined that creates a support ticket using a remote API. - -## Using actions - -Actions can be triggered in two ways: using an HTML [`<form>` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form) or programmatically using the [`useAction` primitive](/solid-router/reference/data-apis/use-action). - -The recommended approach is to use a `<form>` element. -This ensures a robust user experience with progressive enhancement, since the form works even without JavaScript. - -For cases where a form is not suitable, the [`useAction` primitive](/solid-router/reference/data-apis/use-action) can be used to trigger the action programmatically. - -### With the `<form>` element - -Solid Router extends the standard HTML `<form>` element to work with actions. -Form submissions can be handled using action by passing an action to the `action` prop. - -Consider these points when using actions with `<form>`: - -1. The `<form>` element **must** have `method="post"`. -2. The action function will automatically receive the form's data as a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object as its first parameter. -3. For SSR environments, a unique name **must** be provided as the second parameter to the `action` function. - This name is used by Solid Router to identify and serialize the action across the client and server. - -```tsx -import { action } from "@solidjs/router"; - -const submitFeedbackAction = action(async (formData: FormData) => { - const message = formData.get("message")?.toString(); - // ... Sends the feedback to the server. -}, "submitFeedback"); - -function FeedbackForm() { - return ( - <form action={submitFeedbackAction} method="post"> - <textarea name="message" placeholder="Message" /> - <button type="submit">Send feedback</button> - </form> - ); -} -``` - -In this example, when the form is submitted, `submitFeedbackAction` will be triggered with the `FormData` containing the form values. - -:::tip[Uploading files] -If a form includes file inputs, the `<form>` element must have `enctype="multipart/form-data"` to correctly send the file data. - -```tsx -<form action={uploadFileAction} method="post" enctype="multipart/form-data"> - <input type="file" name="myFile" /> - <button type="submit">Upload</button> -</form> -``` - -::: - -#### Passing additional arguments - -Sometimes, an action needs data that isn't part of the form's inputs. -These additional arguments can be passed using the `with` method. - -The `with` method creates a new action that wraps around the original action. -When this new action is triggered, it forwards the arguments specified in the `with` method to the original action, followed by the `FormData` object. - -```tsx -import { action } from "@solidjs/router"; - -const updateProductAction = action( - async (productId: string, formData: FormData) => { - // ... Sends the updated fields to the server. - - return { ok: true }; - }, - "updateProduct" -); - -function EditProductForm(props: { productId: string }) { - return ( - <form action={updateProductAction.with(props.productId)} method="post"> - <input name="name" placeholder="Product name" /> - <button type="submit">Save</button> - </form> - ); -} -``` - -In this example, `updateProductAction` receives `productId` (passed via `with`), and then the `formData` from the form. - -### With the `useAction` primitive - -For scenarios where a `<form>` element is not suitable, the `useAction` primitive provides a way to trigger an action programmatically. -The `useAction` primitive takes an action as its parameter and returns a function that, when called, triggers the action with the provided arguments. - -This approach requires client-side JavaScript and is not progressively enhanceable. - -```tsx -import { action, useAction } from "@solidjs/router"; - -const markNotificationReadAction = action(async (notificationId: string) => { - // ... Marks a notification as read on the server. -}); - -function NotificationItem(props: { id: string }) { - const markRead = useAction(markNotificationReadAction); - - return <button onClick={() => markRead(props.id)}>Mark as read</button>; -} -``` - -In this example, `markRead` is a function that can be called with arguments matching `markNotificationReadAction`. -When the button is clicked, the action is triggered with the provided arguments. - -## Tracking submission state - -When an action is triggered, it creates a **submission** object. -This object is a snapshot of the action's execution, containing its input, current status (pending or complete), and its final result or error. -To access this state, Solid Router provides the [`useSubmission`](/solid-router/reference/data-apis/use-submission) and [`useSubmissions`](/solid-router/reference/data-apis/use-submissions) primitives. - -The `useSubmission` primitive tracks the state of the _most recent_ submission for a specific action. -This is ideal for most use cases, such as disabling a form's submit button while the action is pending or displaying a confirmation message upon success. - -```tsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const updateSettingsAction = action(async (formData: FormData) => { - // ... Sends the settings data to the server. -}, "updateSettings"); - -function UserSettingsForm() { - const submission = useSubmission(updateSettingsAction); - - return ( - <form action={updateSettingsAction} method="post"> - <input name="email" type="email" placeholder="Enter your email" /> - - <button disabled={submission.pending}> - {submission.pending ? "Saving..." : "Save settings"} - </button> - </form> - ); -} -``` - -In this example, the form's submit button is disabled while `submission.pending` is `true`. - -:::tip -To track multiple submissions for a single action, such as in a multi-file uploader interface, the [`useSubmissions` primitive](/solid-router/reference/data-apis/use-submissions) can be used. -::: - -## Handling errors - -An action can fail for various reasons. -A robust application must handle these failures gracefully. -Solid Router provides two mechanisms for an action to signal failure: throwing an `Error` or returning a value. - -Throwing an `Error` is a valid way to signal failure. -Solid Router will catch the thrown error and make it available in the `submission.error` property. -However, this approach has some drawbacks. -The `submission.error` property is typed as `any`, which undermines type safety in the consuming component. -It is also difficult to convey structured error information, such as validation messages for multiple form fields, using a simple `Error` instance. - -For these reasons, the recommended practice is to always `return` a descriptive object from an action to represent its outcome. -The returned object is available in the `submission.result` property, which will be fully typed. -This makes handling different outcomes in the UI simple and safe. - -```tsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const verifyTwoFactorAction = action(async (formData: FormData) => { - const code = formData.get("code")?.toString(); - - if (!code || code.length !== 6) { - return { - ok: false, - errors: { code: "Enter the 6-digit code from the authenticator app." }, - }; - } - - // ... Verifies the code with the server and handles potential errors. - - return { ok: true }; -}, "verifyTwoFactor"); - -function TwoFactorForm() { - const submission = useSubmission(verifyTwoFactorAction); - - const errors = () => { - const result = submission.result; - if (result && !result.ok) { - return result.errors; - } - }; - - return ( - <form action={verifyTwoFactorAction} method="post"> - <div> - <input name="code" placeholder="6-digit code" inputMode="numeric" /> - <Show when={errors()?.code}> - <p>{errors().code}</p> - </Show> - </div> - - <button type="submit" disabled={submission.pending}> - {submission.pending ? "Verifying..." : "Verify"} - </button> - </form> - ); -} -``` - -In this example, the `errors` derived signal inspects `submission.result` to check for failures. -If an `errors` object is found, its properties are used to conditionally render error messages next to the relevant form fields. - -:::caution[Always return a value] -It is important that an action consistently returns a value from all of its possible code paths. -Because, if an action returns `undefined` or `null`, Solid Router removes that submission from its internal list upon completion. -This can lead to unexpected behavior. - -For example, consider an action that returns an error object on failure but returns nothing on success. -If the action fails once, `useSubmission` will correctly report the error. -However, if a subsequent submission succeeds, it will be removed from the list, and `useSubmission` will continue to report the previous stale error state. -To prevent this, ensure every code path in an action returns a value, such as `{ ok: true }` to indicate a successful outcome. -::: - -## Automatic data revalidation - -After server data changes, the application's data can become stale. -To solve this, Solid Router automatically revalidates all [queries](/solid-router/data-fetching/queries) used in the same page after a successful action. -This ensures any component using that data is automatically updated with the freshest information. - -For example, if a page displays a list of registered devices and includes a form to register a new one, the list will automatically update after the form is submitted. - -```tsx -import { For } from "solid-js"; -import { query, action, createAsync } from "@solidjs/router"; - -const getDevicesQuery = query(async () => { - // ... Fetches the list of registered devices. -}, "devices"); - -const registerDeviceAction = action(async (formData: FormData) => { - // ... Registers a new device on the server. -}, "registerDevice"); - -function DevicesPage() { - // This query will automatically revalidate after registerDeviceAction completes. - const devices = createAsync(() => getDevicesQuery()); - - return ( - <div> - <h2>Registered devices</h2> - <For each={devices()}>{(device) => <p>{device.name}</p>}</For> - - <h3>Register new device</h3> - <form action={registerDeviceAction} method="post"> - <input name="name" placeholder="Device name" /> - <button type="submit">Register device</button> - </form> - </div> - ); -} -``` - -While this automatic behavior is convenient for most cases, more fine-grained control may be needed. -The next section explains how to customize or even disable this behavior for specific actions. - -## Managing navigation and revalidation - -While automatic revalidation is powerful, more control is often needed. -It may be desirable to redirect the user to a different page, prevent revalidation entirely, or revalidate a specific set of queries. -This is where response helpers come in. - -Response helpers are functions that create special [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. -When an action returns or throws one of these responses, Solid Router intercepts it and performs a specific task. - -### Redirecting - -To navigate the user to a new page after an action completes, the [`redirect` helper](/solid-router/reference/response-helpers/redirect) can be used. -It can also be used to revalidate specific queries upon redirection, which is useful for updating data that is displayed on the new page. - -```tsx -import { action, redirect } from "@solidjs/router"; -import { useSession } from "vinxi/http"; - -const logoutAction = action(async () => { - "use server"; - const session = await useSession({ - password: process.env.SESSION_SECRET as string, - name: "session", - }); - - if (session.data.sessionId) { - await session.clear(); - await db.session.delete({ id: sessionId }); - } - - throw redirect("/"); -}, "logout"); -``` - -In this example, after a successful login, the `redirect` helper is used to navigate to the dashboard. -It also revalidates the "session" query to ensure the UI reflects the user's authenticated state. - -### Customizing revalidation - -To override the default revalidation behavior, the [`reload`](/solid-router/reference/response-helpers/reload) and [`json`](/solid-router/reference/response-helpers/json) helpers can be used. - -- `reload` is used when only revalidation needs to be customized. -- `json` is used when revalidation needs to be controlled _and_ data needs to be returned from the action. - -Both helpers accept a `revalidate` option, which takes an array of query keys to revalidate. -If an empty array (`[]`) is provided, revalidation is prevented altogether. - -```tsx -import { action, reload, json } from "@solidjs/router"; - -// Example 1: Revalidating a specific query -const savePreferencesAction = action(async () => { - // ... Saves the user preferences. - - // Only revalidate the 'userPreferences' query - throw reload({ revalidate: ["userPreferences"] }); -}); - -// Example 2: Disabling revalidation and returning data -const logActivityAction = action(async () => { - // ... Logs the activity to the server. - - // Return without revalidating any queries - return json({ ok: true }, { revalidate: [] }); -}); -``` - -:::tip[Throwing vs. Returning] -A response helper can be either `return`ed or `throw`n. -In TypeScript, `throw` can be more convenient, as it avoids potential type conflicts with an action's expected return value. -::: - -## Optimistic UI - -Optimistic UI is a pattern where the user interface is updated immediately after a user performs an operation. -This is done without waiting for the server to confirm the operation's success. -This approach makes an application feel faster and more responsive. - -Actions can be combined with local state management to implement optimistic UI. -The `useSubmission` primitive can be used to access the input of an action as it's being submitted. -This input can be used to temporarily update the UI. - -```tsx -import { For, Show } from "solid-js"; -import { query, action, createAsync, useSubmission } from "@solidjs/router"; - -const getCartQuery = query(async () => { - // ... Fetches the current shopping cart items. -}, "cart"); - -const addToCartAction = action(async (formData: FormData) => { - // ... Adds a product to the cart. -}, "addToCart"); - -function CartPage() { - const cart = createAsync(() => getCartQuery()); - const submission = useSubmission(addToCartAction); - - const optimisticCart = () => { - const originalItems = cart() ?? []; - if (submission.pending) { - const formData = submission.input[0] as FormData; - const productId = formData.get("productId")?.toString(); - const name = formData.get("name")?.toString(); - if (productId && name) { - // Add the optimistic line item with a temporary identifier. - return [...originalItems, { id: "temp", productId, name, quantity: 1 }]; - } - } - return originalItems; - }; - - return ( - <div> - <h2>Your cart</h2> - <For each={optimisticCart()}>{(item) => <p>{item.name}</p>}</For> - - <h3>Add item</h3> - <form action={addToCartAction} method="post"> - <input name="productId" placeholder="Product ID" /> - <input name="name" placeholder="Product name" /> - <button type="submit" disabled={submission.pending}> - {submission.pending ? "Adding..." : "Add to cart"} - </button> - </form> - </div> - ); -} -``` - -In this example, a derived signal `optimisticCart` is created. -When an action is pending, it checks the `submission.input` and adds the new cart item to the list with a temporary ID. -If the action fails, `submission.pending` becomes false, and `optimisticCart` will revert to showing the original list from `cart`. -When the action succeeds, Solid Router automatically revalidates `getCartQuery` and updates the UI with the confirmed cart state. - -:::note -For more advanced patterns, consider using [TanStack Query](https://tanstack.com/query/latest/docs/framework/solid/guides/optimistic-updates). -It provides robust tools for managing server state, including cache-based optimistic updates. -::: diff --git a/src/routes/solid-router/(2)rendering-modes/(0)spa.mdx b/src/routes/solid-router/(2)rendering-modes/(0)spa.mdx deleted file mode 100644 index 9629b8928..000000000 --- a/src/routes/solid-router/(2)rendering-modes/(0)spa.mdx +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Single page applications -use_cases: >- - client-side routing, cdn deployment, static hosting, spa configuration, - deployment setup -tags: - - spa - - deployment - - cdn - - hosting - - client-side - - routing -version: "1.0" -description: >- - Configure single-page applications for proper CDN and hosting deployment. - Handle client-side routing without server-side rendering. ---- - -When deploying applications that use a client-side router without relying on Server-Side Rendering, it is important that redirects to the index page are handled properly. -This prevents the CDN or hosting service from returning a "not found" error when accessing URLs that do not correspond to files. - -Each provider has a different way of doing this. -For example, Netlify provides a `_redirects` file that contains: - -```sh frame="none" -/* /index.html 200 -``` - -Vercel, on the other hand, requires a rewrites section in your `vercel.json`: - -```json -{ - "rewrites": [ - { - "source": "/(.*)", - "destination": "/index.html" - } - ] -} -``` diff --git a/src/routes/solid-router/(2)rendering-modes/(1)ssr.mdx b/src/routes/solid-router/(2)rendering-modes/(1)ssr.mdx deleted file mode 100644 index 35666a60c..000000000 --- a/src/routes/solid-router/(2)rendering-modes/(1)ssr.mdx +++ /dev/null @@ -1,31 +0,0 @@ ---- -title: Server side rendering -use_cases: >- - server rendering, seo optimization, initial page load, performance - optimization, data preloading -tags: - - ssr - - server - - rendering - - seo - - performance - - preload -version: "1.0" -description: >- - Enable server-side rendering with Solid Router for SEO and performance. - Support suspense, resources, and render-as-you-fetch patterns. ---- - -Solid Router supports all of Solid's SSR capabilities. -In addition, it has Solid's transitions included, so it can be used freely with [suspense](/reference/components/suspense), [resources](/reference/basic-reactivity/create-resource), and [lazy components](/reference/component-apis/lazy). - -When using SSR, there is the option to use the static router directly or let the browser router default to it on the server by passing in the URL. - -```jsx -import { isServer } from "solid-js/web"; -import { Router } from "@solidjs/router"; - -<Router url={isServer ? req.url : ""} />; -``` - -Solid Router also provides a way to define a `preload` function that loads in parallel to the routes [render-as-you-fetch](https://epicreact.dev/render-as-you-fetch/). diff --git a/src/routes/solid-router/(3)data-fetching/(0)queries.mdx b/src/routes/solid-router/(3)data-fetching/(0)queries.mdx deleted file mode 100644 index 0f43335a6..000000000 --- a/src/routes/solid-router/(3)data-fetching/(0)queries.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: "Queries" ---- - -Queries are the core building blocks for data fetching in Solid Router. -They provide an elegant solution for managing data fetching. - -## Defining queries - -They are defined using the [`query` function](/solid-router/reference/data-apis/query). -It wraps the data-fetching logic and extends it with powerful capabilities like [request deduplication](#deduplication) and [automatic revalidation](#revalidation). - -The `query` function takes two parameters: a **fetcher** and a **name**. - -- The **fetcher** is an asynchronous function that fetches data from any source, such as a remote API. -- The **name** is a unique string used to identify the query. - When a query is called, Solid Router uses this name and the arguments passed to the query to create a unique key, which is used for the internal deduplication mechanism. - -```tsx -import { query } from "@solidjs/router"; - -const getUserProfileQuery = query(async (userId: string) => { - const response = await fetch( - `https://api.example.com/users/${encodeURIComponent(userId)}` - ); - const json = await response.json(); - - if (!response.ok) { - throw new Error(json?.message ?? "Failed to load user profile."); - } - - return json; -}, "userProfile"); -``` - -In this example, the defined query fetches a user's profile from an API. -If the request fails, the fetcher will throw an error that will be caught by the nearest [`<ErrorBoundary>`](/reference/components/error-boundary) in the component tree. - -## Using queries in components - -Defining a query does not by itself fetch any data. -To access its data, the query can be used with the [`createAsync` primitive](/solid-router/reference/data-apis/create-async). -`createAsync` takes an asynchronous function, such as a query, and returns a signal that tracks its result. - -```tsx -import { For, Show } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getArticlesQuery = query(async () => { - // ... Fetches a list of articles from an API. -}, "articles"); - -function Articles() { - const articles = createAsync(() => getArticlesQuery()); - - return ( - <Show when={articles()}> - <For each={articles()}>{(article) => <p>{article.title}</p>}</For> - </Show> - ); -} -``` - -In this example, `createAsync` is used to call the query. -Once the query completes, `articles` holds the result, which is then rendered. - -:::tip -When working with complex data types, such as arrays or deeply nested objects, the [`createAsyncStore` primitive](/solid-router/reference/data-apis/create-async-store) offers a more ergonomic and performant solution. -It works like `createAsync`, but returns a [store](/concepts/stores) for easier state management.. -::: - -## Deduplication - -A key feature of queries is their ability to deduplicate requests, preventing redundant data fetching in quick succession. - -One common use case is preloading: when a user hovers over a link, the application can begin preloading the data for the destination page. -If the user then clicks the link, the query has already been completed, and the data is available instantly without triggering another network request. -This mechanism is fundamental to the performance of Solid Router applications. - -Deduplication also applies when multiple components on the same page use the same query. -As long as at least one component is actively using the query, Solid Router will reuse the cached result instead of refetching the data. diff --git a/src/routes/solid-router/(3)data-fetching/(1)streaming.mdx b/src/routes/solid-router/(3)data-fetching/(1)streaming.mdx deleted file mode 100644 index 42fa45f41..000000000 --- a/src/routes/solid-router/(3)data-fetching/(1)streaming.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: "Streaming" ---- - -In traditional server-rendered applications, the server must fetch all data before rendering and sending the page to the browser. -If some queries are slow, this delays the initial load. -**Streaming** solves this by sending the page’s HTML shell immediately and progressively streaming data-dependent sections as they become ready. - -When a query is accessed during a server-side render, Solid suspends the UI until the data resolves. -By default, this suspension affects the entire page. - -To control this behavior, you can use suspense boundaries - regions of the component tree defined by a [`<Suspense>` component](/reference/components/suspense). -It isolates asynchronous behavior to a specific section of the page. - -Content inside the boundary is managed by Solid’s concurrency system: if it isn’t ready, the boundary’s fallback UI is shown while the rest of the page renders and streams immediately. -Once the data resolves, the server streams the final HTML for that section, replacing the fallback and letting users see and interact with most of the page much sooner. - -```tsx -import { Suspense, For } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getAccountStatsQuery = query(async () => { - // ... Fetches account statistics. -}, "accountStats"); - -const getRecentTransactionsQuery = query(async () => { - // ... Fetches a list of recent transactions. -}, "recentTransactions"); - -function Dashboard() { - const stats = createAsync(() => getAccountStatsQuery()); - const transactions = createAsync(() => getRecentTransactionsQuery()); - - return ( - <div> - <h1>Dashboard</h1> - <Suspense fallback={<p>Loading account stats...</p>}> - <For each={stats()}> - {(stat) => ( - <p> - {stat.label}: {stat.value} - </p> - )} - </For> - </Suspense> - - <Suspense fallback={<p>Loading recent transactions...</p>}> - <For each={transactions()}> - {(transaction) => ( - <h2> - {transaction.description} - {transaction.amount} - </h2> - )} - </For> - </Suspense> - </div> - ); -} -``` - -For example, each `<Suspense>` component creates its own independent boundary. -The server can stream the heading `<h1>Dashboard</h1>` immediately, while the `stats` and `transactions` are handled separately. -If the `transactions` query is slow, only its boundary will display a fallback, while `stats` will render as soon as its data is ready. - -## When to disable streaming - -While streaming is powerful, there are cases where it is better to wait for the data to load on the server. -In these situations, you can use the `deferStream` option in `createAsync`. - -When `deferStream` is set to `true`, the server waits for the query to resolve before sending the initial HTML. - -A common reason to disable streaming is for Search Engine Optimization (SEO). -Some search engine crawlers may not wait for streamed content to load. -If critical data, such as a page title or meta description, affects SEO, it should be included in the initial server response. - -```tsx -import { query, createAsync } from "@solidjs/router"; - -const getArticleQuery = query(async () => { - // ... Fetches an article. -}, "article"); - -function ArticleHeader() { - const article = createAsync(() => getArticleQuery(), { - deferStream: true, - }); - - return <h1>{article()?.title}</h1>; -} -``` diff --git a/src/routes/solid-router/(3)data-fetching/(2)revalidation.mdx b/src/routes/solid-router/(3)data-fetching/(2)revalidation.mdx deleted file mode 100644 index cf507c438..000000000 --- a/src/routes/solid-router/(3)data-fetching/(2)revalidation.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: "Revalidation" ---- - -Since server data can change, Solid Router provides mechanisms to revalidate queries and keep the UI up to date. - -The most common case is **automatic revalidation**. -After an [action](/solid-router/concepts/actions) completes successfully, Solid Router automatically revalidates all active queries on the page. -For more details, see the [actions documentation](/solid-router/concepts/actions#automatic-data-revalidation). - -For more fine-grained control, you can trigger revalidation manually with the [`revalidate` function](/solid-router/reference/data-apis/revalidate). -It accepts a query key (or an array of keys) to target specific queries. -Each query exposes two properties for this: `key` and `keyFor`. - -- `query.key` is the base key for a query and targets all of its instances. - Using this key will revalidate all data fetched by that query, regardless of the arguments provided. -- `query.keyFor(arguments)` generates a key for a specific set of arguments, allowing you to target and revalidate only that particular query. - -```tsx -import { For } from "solid-js"; -import { query, createAsync, revalidate } from "@solidjs/router"; - -const getProjectsQuery = query(async () => { - // ... Fetches a list of projects. -}, "projects"); - -const getProjectTasksQuery = query(async (projectId: string) => { - // ... Fetches a list of tasks for a project. -}, "projectTasks"); - -function Projects() { - const projects = createAsync(() => getProjectsQuery()); - - function refetchAllTasks() { - revalidate(getProjectTasksQuery.key); - } - - return ( - <div> - <button onClick={refetchAllTasks}>Refetch all tasks</button> - <For each={projects()}>{(project) => <Project id={project.id} />}</For> - </div> - ); -} - -function Project(props: { id: string }) { - const tasks = createAsync(() => getProjectTasksQuery(props.id)); - - function refetchTasks() { - revalidate(getProjectTasksQuery.keyFor(props.id)); - } - - return ( - <div> - <button onClick={refetchTasks}>Refetch tasks for this project</button> - <For each={tasks()}>{(task) => <div>{task.title}</div>}</For> - </div> - ); -} -``` diff --git a/src/routes/solid-router/(3)data-fetching/how-to/(0)preload-data.mdx b/src/routes/solid-router/(3)data-fetching/how-to/(0)preload-data.mdx deleted file mode 100644 index 39215abe6..000000000 --- a/src/routes/solid-router/(3)data-fetching/how-to/(0)preload-data.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: "Preload data" ---- - -Preloading data improves perceived performance by fetching the data for an upcoming page before the user navigates to it. - -Solid Router initiates preloading in two scenarios: - -- When a user indicates intent to navigate to the page (e.g., by hovering over a link). -- When the route's component is rendering. - -This ensures data fetching starts as early as possible, often making data ready once the component renders. - -Preloading is configured using the [`preload`](/solid-router/reference/preload-functions/preload) prop on a [`Route`](/solid-router/reference/components/route). -This prop accepts a function that calls one or more queries. -When triggered, the queries execute and their results are stored in a short-lived internal cache. -Once the user navigates and the destination route’s component renders, any `createAsync` calls within the page will consume the preloaded data. -Thanks to the [deduplication mechanism](#deduplication), no redundant network requests are made. - -```tsx {18-20,27} -import { Show } from "solid-js"; -import { Route, query, createAsync } from "@solidjs/router"; - -const getProductQuery = query(async (id: string) => { - // ... Fetches product details for the given ID. -}, "product"); - -function ProductDetails(props) { - const product = createAsync(() => getProductQuery(props.params.id)); - - return ( - <Show when={product()}> - <h1>{product().name}</h1> - </Show> - ); -} - -function preloadProduct({ params }: { params: { id: string } }) { - getProductQuery(params.id); -} - -function Routes() { - return ( - <Route - path="/products/:id" - component={ProductDetails} - preload={preloadProduct} - /> - ); -} -``` - -In this example, hovering a link to `/products/:id` triggers `preloadProduct`. -When the `ProductDetails` component renders, its `createAsync` call will instantly resolve with the preloaded data. diff --git a/src/routes/solid-router/(3)data-fetching/how-to/(1)handle-error-and-loading-states.mdx b/src/routes/solid-router/(3)data-fetching/how-to/(1)handle-error-and-loading-states.mdx deleted file mode 100644 index 2f559a617..000000000 --- a/src/routes/solid-router/(3)data-fetching/how-to/(1)handle-error-and-loading-states.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: "Handle pending and error states" ---- - -The `createAsync` primitive is designed to work with Solid's native components for managing asynchronous states. -It reports its pending state to the nearest [`<Suspense>` boundary](/reference/components/suspense) to display loading fallbacks, and propagate errors to an [`<ErrorBoundary>`](/reference/components/error-boundary) for handling and displaying error messages. - -```tsx -import { Suspense, ErrorBoundary, For } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getNewsQuery = query(async () => { - // ... Fetches the latest news from an API. -}, "news"); - -function NewsFeed() { - const news = createAsync(() => getNewsQuery()); - - return ( - <ErrorBoundary fallback={<p>Could not fetch news.</p>}> - <Suspense fallback={<p>Loading news...</p>}> - <ul> - <For each={news()}>{(item) => <li>{item.headline}</li>}</For> - </ul> - </Suspense> - </ErrorBoundary> - ); -} -``` diff --git a/src/routes/solid-router/(4)advanced-concepts/(0)preloading.mdx b/src/routes/solid-router/(4)advanced-concepts/(0)preloading.mdx deleted file mode 100644 index 73b949287..000000000 --- a/src/routes/solid-router/(4)advanced-concepts/(0)preloading.mdx +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: Preloading ---- - -Preloading smooths navigation by resolving route code and data before a user completes a transition. -Solid Router listens for intent signals, such as hover and focus, and primes the matching route after a short delay to balance responsiveness and network cost. -Understanding the timing and scope of this work lets you decide when to rely on the default behaviour and when to layer custom strategies. - -| user action | route behaviour | -| ----------- | ------------------------------------- | -| hover | waits roughly 20 ms before preloading | -| focus | preloads immediately | - -## How Solid Router Detects Intent - -Anchors registered with Solid Router emit hover and focus events that feed a small scheduler. -The router debounces the hover signal for 20ms to ignore incidental pointer passes while still reacting quickly to purposeful movement. -When the delay elapses, the router loads the route module and runs its preload routine so that navigation has the assets it needs when the user commits. - -Route modules can export a [`preload`](/solid-router/reference/preload-functions/preload) function that receives params, search values, and router context. -The function lets you seed caches, warm derived computations, or coordinate streaming behaviours without blocking the eventual render. - -> [!NOTE] -> SSR invokes route `preload` functions during the initial server render and resumes them on the client during hydration. -> Keep these functions pure so the hydrated client does not need to undo server work when it takes over. - -## Imperative Preloading Hooks - -Not every interaction funnels through an anchor element. -The [`usePreloadRoute`](/solid-router/reference/primitives/use-preload-route) primitive exposes the same scheduling behaviour for imperative flows like flyout previews, timers, or observer driven experiences. - -This helper mirrors the router behaviour by resolving the module, optionally running the loader, and caching the result for the eventual navigation. -Empirical tuning of delay values helps you avoid excessive prefetching in dense UIs while still keeping high intent interactions snappy. - -## Coordinating Nested Lazy Components - -Nested lazy components live outside the router hierarchy, so route preloading does not automatically warm them. -The component API [`lazy()`](/reference/component-apis/lazy) exposes a `preload()` method that resolves a component without rendering it. -Calling both the route preload and the nested component preload can keep large detail panels responsive when a user hovers or focuses on the entry point. - -Balancing manual preloading requires observing real user flows so you avoid prefetching large bundles that the user never requests. -Profiling tools help you spot whether preloading reduces long tasks or simply shifts work earlier without net gains. - -To learn more about lazy loading components, see the [lazy documentation](/reference/component-apis/lazy#preloading-data-in-nested-lazy-components). diff --git a/src/routes/solid-router/(4)advanced-concepts/(1)lazy-loading.mdx b/src/routes/solid-router/(4)advanced-concepts/(1)lazy-loading.mdx deleted file mode 100644 index bc2055bf2..000000000 --- a/src/routes/solid-router/(4)advanced-concepts/(1)lazy-loading.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Lazy loading -use_cases: >- - optimizing bundle size, code splitting, reducing initial load, large apps, - performance optimization -tags: - - lazy - - performance - - routing - - optimization - - splitting - - loading -version: "1.0" -description: >- - Implement lazy loading in Solid Router to reduce initial bundle size. Load - components on-demand for better performance in large applications. ---- - -Lazy loading allows you to load only the necessary resources when they are needed. -This can be useful when you have a large application with a lot of routes and components, and you want to reduce the initial load time. - -In Solid Router, you can lazy load components using the `lazy` function from Solid: - -```jsx -import { lazy } from "solid-js"; -import { Router, Route } from "@solidjs/router"; - -const Home = lazy(() => import("./Home")); - -const Users = lazy(() => import("./Users")); - -const App = () => ( - <Router> - <Route path="/" component={Home} /> - <Route path="/users" component={Users} /> - </Router> -); -``` - -In the example above, the `Users` component is lazy loaded using the `lazy` function. -The `lazy` function takes a function that returns a promise, which resolves to the component you want to load. -When the route is matched, the component will be loaded and rendered. diff --git a/src/routes/solid-router/(5)guides/(0)migration.mdx b/src/routes/solid-router/(5)guides/(0)migration.mdx deleted file mode 100644 index b7d4bec00..000000000 --- a/src/routes/solid-router/(5)guides/(0)migration.mdx +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: Migration from v0.9.x -use_cases: >- - upgrading from v0.9, breaking changes, api migration, updating legacy code, - version upgrade -tags: - - migration - - upgrade - - breaking-changes - - v0.10 - - api-changes - - legacy -version: "1.0" -description: >- - Migrate your Solid Router application to v0.10 with this comprehensive guide - covering removed APIs, new patterns, and Islands support changes. ---- - -v0.10.0 brings some big changes to support the future of routing including Islands/Partial Hydration hybrid solutions. -Most notably there is no Context API available in non-hydrating parts of the application. - -The biggest changes are around _removed APIs_ that need to be replaced. - -## `<Outlet>`, `<Routes>`, `useRoutes` - -These components are no longer present in the new router version. Instead, `props.children` is passed into the page components in the place of outlets. -This keeps the outlet directly passed from its page and avoids trying to use context across Islands boundaries. -Similarly, nested `<Routes>` components cause waterfalls and are `<Outlets>` themselves thus sharing the same concerns. - -With no `<Routes>` means the `<Router>` API has changed. -The `<Router>` component acts as the `<Routes>` component now and its children must now be `<Route>` components. -The top-level layout should go in the root prop of the router [as shown here](/solid-router/concepts/layouts#root-level-layouts). - -## `element` prop removed from `Route` - -Related without Outlet component it has to be passed in manually. -At which point the `element` prop has less value. -Removing the second way to define route components to reduce confusion and edge cases. - -## `data` functions & `useRouteData` - -`data` functions & `useRouteData` have been replaced by a load mechanism. -This allows link hover preloads, since the preload function can be run as much as wanted without worrying about reactivity. - -This supports deduping/cache APIs which give more control over how things are cached. -It also addresses TypeScript issues with getting the right types in the Component without `typeof` checks. - -That being said the old pattern can be reproduced by turning off preloads at the router level and then injecting your own Context: - -```js -import { lazy } from "solid-js"; -import { Router, Route } from "@solidjs/router"; - -const User = lazy(() => import("./pages/users/[id].js")); - -// preload function -function preloadUser({ params, location }) { - const [user] = createResource(() => params.id, fetchUser); - return user; -} - -// Pass it in the route definition -<Router preload={false}> - <Route path="/users/:id" component={User} preload={preloadUser} /> -</Router>; -``` - -And then in your component taking the page props and putting them in a Context. - -```js -import { createContext, useContext } from "solid-js"; - -const UserContext = createContext(); - -function User(props) { - <UserContext.Provider value={props.data()}> - {/* my component content that includes <UserDetails /> in any depth */} - </UserContext.Provider>; -} - -function UserDetails() { - const user = useContext(UserContext); - // render stuff -} -``` diff --git a/src/routes/solid-router/reference/components/a.mdx b/src/routes/solid-router/reference/components/a.mdx deleted file mode 100644 index 6b99bb348..000000000 --- a/src/routes/solid-router/reference/components/a.mdx +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: A -use_cases: >- - navigation links, active link styling, relative paths, route links -tags: - - component - - navigation - - links - - active-states -version: "1.0" -description: >- - A wraps a native anchor element for Solid Router navigation. ---- - -`A` wraps the native [`<a>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) element with Solid Router path resolution, active-state classes, and the router `link` marker used by delegated navigation handling. - -## Import - -```tsx -import { A } from "@solidjs/router"; -``` - -## Type - -```tsx -interface AnchorProps extends Omit< - JSX.AnchorHTMLAttributes<HTMLAnchorElement>, - "state" -> { - href: string; - replace?: boolean; - noScroll?: boolean; - state?: unknown; - inactiveClass?: string; - activeClass?: string; - end?: boolean; -} - -function A(props: AnchorProps): JSX.Element; -``` - -## Props - -Besides the router props below, `A` accepts native [`<a>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) attributes except `state`, which Solid Router defines separately. - -### `href` - -- **Type:** `string` -- **Optional:** No - -Path passed to the router and rendered as the anchor `href`. - -### `replace` - -- **Type:** `boolean` -- **Optional:** Yes - -Forwarded to the rendered anchor for router navigation handling. - -### `noScroll` - -- **Type:** `boolean` -- **Optional:** Yes - -Forwarded to the rendered anchor for router navigation handling. - -### `state` - -- **Type:** `unknown` -- **Optional:** Yes - -Value serialized onto the rendered anchor for router navigation handling. - -### `inactiveClass` - -- **Type:** `string` -- **Default:** `"inactive"` -- **Optional:** Yes - -Class applied when the link does not match the current location. - -### `activeClass` - -- **Type:** `string` -- **Default:** `"active"` -- **Optional:** Yes - -Class applied when the link matches the current location. - -### `end` - -- **Type:** `boolean` -- **Optional:** Yes - -Controls whether active matching requires an exact pathname match. - -## Behavior - -- Renders a native `a` element, spreads remaining anchor attributes onto it, and adds the router `link` attribute. -- Resolves `href` against the current route and renders the router-rendered path when one is available. -- Active matching compares the normalized current pathname to the normalized target pathname. Without `end`, descendant paths also match. -- When the link is an exact match, `A` sets `aria-current="page"`. -- `state` is serialized with `JSON.stringify` before being passed to the rendered anchor. -- Requires a router context. - -## Examples - -### Basic usage - -```tsx -import { A, Route, Router } from "@solidjs/router"; - -function Layout(props) { - return ( - <> - <nav> - <A href="/">Home</A> - <A href="/docs" activeClass="selected"> - Docs - </A> - </nav> - {props.children} - </> - ); -} - -export default function App() { - return ( - <Router root={Layout}> - <Route path="/" component={() => <h1>Home</h1>} /> - <Route path="/docs" component={() => <h1>Docs</h1>} /> - </Router> - ); -} -``` - -## Related - -- [`Router`](/solid-router/reference/components/router) -- [`useNavigate`](/solid-router/reference/primitives/use-navigate) diff --git a/src/routes/solid-router/reference/components/hash-router.mdx b/src/routes/solid-router/reference/components/hash-router.mdx deleted file mode 100644 index f432a4239..000000000 --- a/src/routes/solid-router/reference/components/hash-router.mdx +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: HashRouter -use_cases: >- - hash routing, client routing, static deployments -tags: - - hash-routing - - client-side - - component - - router -version: "1.0" -description: >- - HashRouter stores route paths in the URL hash. ---- - -`HashRouter` is the browser router variant that keeps the route in the URL fragment. It reads and writes `window.location.hash`, so routed URLs render as hash paths such as `#/docs` instead of pathname URLs such as `/docs`. - -## Import - -```tsx -import { HashRouter } from "@solidjs/router"; -``` - -## Type - -```tsx -type BaseRouterProps = { - base?: string; - root?: Component<RouteSectionProps>; - rootPreload?: RoutePreloadFunc; - singleFlight?: boolean; - children?: JSX.Element | RouteDefinition | RouteDefinition[]; - transformUrl?: (url: string) => string; - rootLoad?: RoutePreloadFunc; -}; - -type HashRouterProps = BaseRouterProps & { - actionBase?: string; - explicitLinks?: boolean; - preload?: boolean; -}; - -function HashRouter(props: HashRouterProps): JSX.Element; -``` - -## Props - -### `children` - -- **Type:** `JSX.Element | RouteDefinition | RouteDefinition[]` -- **Optional:** Yes - -Route definitions rendered by the router. - -### `base` - -- **Type:** `string` -- **Default:** `""` -- **Optional:** Yes - -Base path used when creating route branches. - -### `root` - -- **Type:** `Component<RouteSectionProps>` -- **Optional:** Yes - -Component rendered around matched routes. - -### `rootPreload` - -- **Type:** `RoutePreloadFunc` -- **Optional:** Yes - -Preload function called for the root route context. - -### `singleFlight` - -- **Type:** `boolean` -- **Default:** `true` -- **Optional:** Yes - -Controls the router context `singleFlight` setting. - -### `transformUrl` - -- **Type:** `(url: string) => string` -- **Optional:** Yes - -Function applied to the location pathname before route matching. - -### `actionBase` - -- **Type:** `string` -- **Default:** `"/_server"` -- **Optional:** Yes - -Base path used by native form action handling. - -### `explicitLinks` - -- **Type:** `boolean` -- **Default:** `false` -- **Optional:** Yes - -Controls whether native anchor interception requires the `link` attribute. - -### `preload` - -- **Type:** `boolean` -- **Default:** `true` -- **Optional:** Yes - -Controls router-managed anchor preloading. - -## Behavior - -- Reads the route source from `window.location.hash.slice(1)`. -- Navigation writes `"#" + value` with `window.history.pushState` or `window.history.replaceState`. -- Rendered paths have a leading `#`. -- Listens for `hashchange` events. -- Hash-only hrefs that do not start with `/` are parsed as hashes on the current path. - -## Examples - -### Basic usage - -```tsx -import { render } from "solid-js/web"; -import { HashRouter, Route } from "@solidjs/router"; - -render( - () => ( - <HashRouter> - <Route path="/" component={() => <h1>Home</h1>} /> - </HashRouter> - ), - document.getElementById("root")! -); -``` - -## Related - -- [`Router`](/solid-router/reference/components/router) -- [`Route`](/solid-router/reference/components/route) -- [`A`](/solid-router/reference/components/a) diff --git a/src/routes/solid-router/reference/components/memory-router.mdx b/src/routes/solid-router/reference/components/memory-router.mdx deleted file mode 100644 index c268f9340..000000000 --- a/src/routes/solid-router/reference/components/memory-router.mdx +++ /dev/null @@ -1,173 +0,0 @@ ---- -title: MemoryRouter -use_cases: >- - memory routing, controlled history, tests, internal navigation state -tags: - - memory - - history - - component - - router -version: "1.0" -description: >- - MemoryRouter stores route paths in a memory history object. ---- - -`MemoryRouter` keeps the router location in a `MemoryHistory` object instead of the browser address bar. It is for route state owned by code, with navigation controlled through `history.get`, `history.set`, `history.go`, and `history.listen`. - -## Import - -```tsx -import { MemoryRouter, createMemoryHistory } from "@solidjs/router"; -``` - -## Type - -```tsx -type BaseRouterProps = { - base?: string; - root?: Component<RouteSectionProps>; - rootPreload?: RoutePreloadFunc; - singleFlight?: boolean; - children?: JSX.Element | RouteDefinition | RouteDefinition[]; - transformUrl?: (url: string) => string; - rootLoad?: RoutePreloadFunc; -}; - -type MemoryHistory = { - get: () => string; - set: (change: LocationChange) => void; - go: (delta: number) => void; - listen: (listener: (value: string) => void) => () => void; -}; - -type MemoryRouterProps = BaseRouterProps & { - history?: MemoryHistory; - actionBase?: string; - explicitLinks?: boolean; - preload?: boolean; -}; - -function createMemoryHistory(): MemoryHistory & { - back: () => void; - forward: () => void; -}; - -function MemoryRouter(props: MemoryRouterProps): JSX.Element; -``` - -## Props - -### `history` - -- **Type:** `MemoryHistory` -- **Default:** `createMemoryHistory()` -- **Optional:** Yes - -Memory history object used as the router source. - -### `children` - -- **Type:** `JSX.Element | RouteDefinition | RouteDefinition[]` -- **Optional:** Yes - -Route definitions rendered by the router. - -### `base` - -- **Type:** `string` -- **Default:** `""` -- **Optional:** Yes - -Base path used when creating route branches. - -### `root` - -- **Type:** `Component<RouteSectionProps>` -- **Optional:** Yes - -Component rendered around matched routes. - -### `rootPreload` - -- **Type:** `RoutePreloadFunc` -- **Optional:** Yes - -Preload function called for the root route context. - -### `singleFlight` - -- **Type:** `boolean` -- **Default:** `true` -- **Optional:** Yes - -Controls the router context `singleFlight` setting. - -### `transformUrl` - -- **Type:** `(url: string) => string` -- **Optional:** Yes - -Function applied to the location pathname before route matching. - -### `actionBase` - -- **Type:** `string` -- **Default:** `"/_server"` -- **Optional:** Yes - -Base path used by native form action handling. - -### `explicitLinks` - -- **Type:** `boolean` -- **Default:** `false` -- **Optional:** Yes - -Controls whether native anchor interception requires the `link` attribute. - -### `preload` - -- **Type:** `boolean` -- **Default:** `true` -- **Optional:** Yes - -Controls router-managed anchor preloading. - -## Return value - -- **Type:** `MemoryHistory & { back: () => void; forward: () => void }` - -`createMemoryHistory` returns a memory history object. - -## Behavior - -- Uses the provided `history` prop. If `history` is omitted, it creates a new memory history. -- `createMemoryHistory` starts with `"/"` at index `0`. -- `history.set` replaces the current entry when `replace` is truthy. Otherwise, it removes entries after the current index and appends the next value. -- `history.go` clamps the next index between the first and last history entries. -- `history.listen` registers a listener and returns a cleanup function that removes it. - -## Examples - -### Basic usage - -```tsx -import { MemoryRouter, Route, createMemoryHistory } from "@solidjs/router"; - -export default function App() { - const history = createMemoryHistory(); - - return ( - <MemoryRouter history={history}> - <Route path="/" component={() => <h1>Home</h1>} /> - <Route path="/about" component={() => <h1>About</h1>} /> - </MemoryRouter> - ); -} -``` - -## Related - -- [`Router`](/solid-router/reference/components/router) -- [`HashRouter`](/solid-router/reference/components/hash-router) -- [`Route`](/solid-router/reference/components/route) diff --git a/src/routes/solid-router/reference/components/navigate.mdx b/src/routes/solid-router/reference/components/navigate.mdx deleted file mode 100644 index 7509bc183..000000000 --- a/src/routes/solid-router/reference/components/navigate.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Navigate -use_cases: >- - redirects, programmatic navigation, render-time navigation -tags: - - component - - redirects - - navigation -version: "1.0" -description: >- - Navigate performs router navigation when it renders. ---- - -`Navigate` performs router navigation during render and returns no UI. It is the component form of a redirect, not an anchor link. - -## Import - -```tsx -import { Navigate } from "@solidjs/router"; -``` - -## Type - -```tsx -interface NavigateProps { - href: - ((args: { navigate: Navigator; location: Location }) => string) | string; - state?: unknown; -} - -function Navigate(props: NavigateProps): null; -``` - -## Props - -### `href` - -- **Type:** `((args: { navigate: Navigator; location: Location }) => string) | string` -- **Optional:** No - -Path to navigate to, or a function that receives the router navigator and current location and returns a path. - -### `state` - -- **Type:** `unknown` -- **Optional:** Yes - -State passed to the router navigator. - -## Behavior - -- Calls `useNavigate` and `useLocation` when rendered. -- If `href` is a function, it receives `{ navigate, location }` before navigation. -- Navigation uses `{ replace: true, state }`. -- Renders `null`. - -## Examples - -### Basic usage - -```tsx -import { Navigate, Route, Router } from "@solidjs/router"; - -export default function App() { - return ( - <Router> - <Route path="/old" component={() => <Navigate href="/new" />} /> - </Router> - ); -} -``` - -### Function href - -```tsx -import { Navigate, Route, Router } from "@solidjs/router"; - -function getPath({ location }) { - return location.pathname === "/old" ? "/new" : "/"; -} - -export default function App() { - return ( - <Router> - <Route path="/old" component={() => <Navigate href={getPath} />} /> - </Router> - ); -} -``` - -## Related - -- [`A`](/solid-router/reference/components/a) -- [`useNavigate`](/solid-router/reference/primitives/use-navigate) -- [`useLocation`](/solid-router/reference/primitives/use-location) diff --git a/src/routes/solid-router/reference/components/route.mdx b/src/routes/solid-router/reference/components/route.mdx deleted file mode 100644 index 6eaa91ef1..000000000 --- a/src/routes/solid-router/reference/components/route.mdx +++ /dev/null @@ -1,121 +0,0 @@ ---- -title: Route -use_cases: >- - route definitions, path matching, nested routes, route preload -tags: - - component - - routes - - routing - - configuration -version: "1.0" -description: >- - Route defines a matchable route segment. ---- - -`Route` creates a route definition. It describes a path segment, the component for the match, route data setup, metadata, and nested child routes. - -## Import - -```tsx -import { Route } from "@solidjs/router"; -``` - -## Type - -```tsx -type RouteProps<S extends string, T = unknown> = { - path?: S | S[]; - children?: JSX.Element; - preload?: RoutePreloadFunc<T>; - matchFilters?: MatchFilters<S>; - component?: Component<RouteSectionProps<T>>; - info?: Record<string, any>; - load?: RoutePreloadFunc<T>; -}; - -function Route<S extends string, T = unknown>( - props: RouteProps<S, T> -): JSX.Element; -``` - -## Props - -### `path` - -- **Type:** `S | S[]` -- **Optional:** Yes - -Path segment or path segments matched by the route. - -### `children` - -- **Type:** `JSX.Element` -- **Optional:** Yes - -Nested route definitions below this segment. - -### `preload` - -- **Type:** `RoutePreloadFunc<T>` -- **Optional:** Yes - -Function called for route preloading and route data setup. - -### `matchFilters` - -- **Type:** `MatchFilters<S>` -- **Optional:** Yes - -Additional constraints for path parameter matching. - -### `component` - -- **Type:** `Component<RouteSectionProps<T>>` -- **Optional:** Yes - -Component rendered for this route match. - -### `info` - -- **Type:** `Record<string, any>` -- **Optional:** Yes - -Route metadata stored on the route definition. - -### `load` - -- **Type:** `RoutePreloadFunc<T>` -- **Optional:** Yes - -Deprecated alias for `preload`. - -## Behavior - -- Resolves `children` and returns the route props as a route definition object. -- When route branches are created, `preload` is used for route preloading. If `preload` is absent, `load` is used. -- Array `path` values create one route description per path. - -## Examples - -### Basic usage - -```tsx -import { Route, Router } from "@solidjs/router"; - -function Home() { - return <h1>Home</h1>; -} - -export default function App() { - return ( - <Router> - <Route path="/" component={Home} /> - </Router> - ); -} -``` - -## Related - -- [`Router`](/solid-router/reference/components/router) -- [`preload`](/solid-router/reference/preload-functions/preload) diff --git a/src/routes/solid-router/reference/components/router.mdx b/src/routes/solid-router/reference/components/router.mdx deleted file mode 100644 index aeb80d8c4..000000000 --- a/src/routes/solid-router/reference/components/router.mdx +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Router -use_cases: >- - routing context, browser routing, route definitions, app routing -tags: - - component - - router - - routing - - context -version: "1.0" -description: >- - Router provides browser-based routing context for Solid Router. ---- - -`Router` is the browser router component that provides routing context for route definitions and router primitives. - -## Import - -```tsx -import { Router } from "@solidjs/router"; -``` - -## Type - -```tsx -type RouterProps = BaseRouterProps & { - url?: string; - actionBase?: string; - explicitLinks?: boolean; - preload?: boolean; -}; - -type BaseRouterProps = { - base?: string; - root?: Component<RouteSectionProps>; - rootPreload?: RoutePreloadFunc; - singleFlight?: boolean; - children?: JSX.Element | RouteDefinition | RouteDefinition[]; - transformUrl?: (url: string) => string; - rootLoad?: RoutePreloadFunc; -}; - -function Router(props: RouterProps): JSX.Element; -``` - -## Props - -### `children` - -- **Type:** `JSX.Element | RouteDefinition | RouteDefinition[]` -- **Optional:** Yes - -Route definitions rendered by the router. - -### `base` - -- **Type:** `string` -- **Default:** `""` -- **Optional:** Yes - -Base path used when creating route branches. - -### `root` - -- **Type:** `Component<RouteSectionProps>` -- **Optional:** Yes - -Component rendered around matched routes. - -### `rootPreload` - -- **Type:** `RoutePreloadFunc` -- **Optional:** Yes - -Preload function called for the root route context. - -### `singleFlight` - -- **Type:** `boolean` -- **Default:** `true` -- **Optional:** Yes - -Controls the router context `singleFlight` setting. - -### `transformUrl` - -- **Type:** `(url: string) => string` -- **Optional:** Yes - -Function applied to the location pathname before route matching. - -### `url` - -- **Type:** `string` -- **Optional:** Yes - -Initial URL used by the server-side static router path. - -### `actionBase` - -- **Type:** `string` -- **Default:** `"/_server"` -- **Optional:** Yes - -Base path used by native form action handling. - -### `explicitLinks` - -- **Type:** `boolean` -- **Default:** `false` -- **Optional:** Yes - -Controls whether native anchor interception requires the `link` attribute. - -### `preload` - -- **Type:** `boolean` -- **Default:** `true` -- **Optional:** Yes - -Controls router-managed anchor preloading. - -## Behavior - -- On the server, `Router` delegates to `StaticRouter`. -- Client routing reads the current path from `window.location.pathname`, `window.location.search`, and `window.location.hash`. -- Navigation writes with `window.history.pushState` or `window.history.replaceState`. -- Hash scrolling uses the decoded hash target when one is present. -- Native anchor, preload, and form action event handlers are installed on the client. - -## Examples - -### Basic usage - -```tsx -import { render } from "solid-js/web"; -import { Route, Router } from "@solidjs/router"; - -function Layout(props) { - return ( - <> - <h1>Root header</h1> - {props.children} - </> - ); -} - -render( - () => ( - <Router root={Layout}> - <Route path="/" component={() => <h2>Home</h2>} /> - </Router> - ), - document.getElementById("root")! -); -``` - -## Related - -- [`Route`](/solid-router/reference/components/route) -- [`A`](/solid-router/reference/components/a) -- [`HashRouter`](/solid-router/reference/components/hash-router) -- [`MemoryRouter`](/solid-router/reference/components/memory-router) diff --git a/src/routes/solid-router/reference/data-apis/action.mdx b/src/routes/solid-router/reference/data-apis/action.mdx deleted file mode 100644 index fe1f40025..000000000 --- a/src/routes/solid-router/reference/data-apis/action.mdx +++ /dev/null @@ -1,146 +0,0 @@ ---- -title: action -use_cases: >- - actions, form actions, mutations, submissions -tags: - - actions - - forms - - mutations - - submissions -version: "1.0" -description: >- - action wraps an async function as a router action. ---- - -`action` wraps an async function and returns an action function with router submission tracking. Matching submissions can be read with [`useSubmission`](/solid-router/reference/data-apis/use-submission) and [`useSubmissions`](/solid-router/reference/data-apis/use-submissions). - -## Import - -```tsx -import { action } from "@solidjs/router"; -``` - -## Type - -```tsx -function action<T extends Array<any>, U = void>( - fn: (...args: T) => Promise<U>, - name?: string -): Action<T, U>; - -function action<T extends Array<any>, U = void>( - fn: (...args: T) => Promise<U>, - options?: { - name?: string; - onComplete?: (submission: Submission<T, U>) => void; - } -): Action<T, U>; -``` - -## Parameters - -### `fn` - -- **Type:** `(...args: T) => Promise<U>` -- **Required:** Yes - -Async function called when the action runs. - -When native form handling calls the action, the argument is `FormData` for `multipart/form-data` forms and `URLSearchParams` otherwise. - -### `options` - -- **Type:** `{ name?: string; onComplete?: (submission: Submission<T, U>) => void }` -- **Required:** No - -Action options. - -#### `name` - -- **Type:** `string` -- **Required:** No - -Name used to create the action URL when passing an options object. - -#### `onComplete` - -- **Type:** `(submission: Submission<T, U>) => void` -- **Required:** No - -Function called after the action response is handled. - -## Return value - -`action` returns a function with the following properties: - -### `url` - -- **Type:** `string` - -String used when the action is rendered as a form `action` and when submissions are matched back to this action. The optional `name` provides a stable value for this string. - -### `with` - -- **Type:** `(...args: any[]) => Action<any[], U>` - -Function that creates an action with leading arguments prefilled. - -## Behavior - -- Calling an action adds a submission to the router submissions signal. -- Each submission exposes `input`, `url`, `result`, `error`, `pending`, `clear`, and `retry`. -- `with` creates another action that calls the original action with leading arguments already supplied. -- `onComplete` receives a submission snapshot after the response is handled. -- `Response` objects with an `X-Revalidate` header supply the keys passed to `revalidate`; without that header, action response handling passes `undefined`. -- Returned `Response` objects with a `Location` header trigger client navigation to that location. -- On the client, actions are registered by URL in the action map and removed during cleanup when an owner exists. -- If an action has no URL, converting it to a string throws. - -## Examples - -### Basic usage - -```tsx -import { action } from "@solidjs/router"; - -const addTodo = action(async (data: URLSearchParams) => { - return data.get("title")?.toString(); -}, "addTodo"); - -function TodoForm() { - return ( - <form action={addTodo} method="post"> - <input name="title" /> - <button>Add todo</button> - </form> - ); -} -``` - -### Prefilled arguments - -```tsx -import { action } from "@solidjs/router"; - -const addTodo = action(async (userId: string, data: URLSearchParams) => { - return { - userId, - title: data.get("title")?.toString(), - }; -}, "addTodo"); - -function TodoForm(props: { userId: string }) { - return ( - <form action={addTodo.with(props.userId)} method="post"> - <input name="title" /> - <button>Add todo</button> - </form> - ); -} -``` - -## Related - -- [`useAction`](/solid-router/reference/data-apis/use-action) -- [`useSubmission`](/solid-router/reference/data-apis/use-submission) -- [`useSubmissions`](/solid-router/reference/data-apis/use-submissions) diff --git a/src/routes/solid-router/reference/data-apis/cache.mdx b/src/routes/solid-router/reference/data-apis/cache.mdx deleted file mode 100644 index e2e14c98e..000000000 --- a/src/routes/solid-router/reference/data-apis/cache.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: cache -isDeprecated: true -use_cases: >- - deprecated query alias, cached functions, route data -tags: - - cache - - deprecated - - query -version: "1.0" -description: >- - cache is a deprecated alias for query. ---- - -`cache` is a deprecated alias for [`query`](/solid-router/reference/data-apis/query). - -## Import - -```tsx -import { cache } from "@solidjs/router"; -``` - -## Type - -```tsx -const cache: typeof query; -``` - -## Parameters - -`cache` has the same parameters as [`query`](/solid-router/reference/data-apis/query). - -## Return value - -- **Type:** `CachedFunction<T>` - -`cache` returns the same value as [`query`](/solid-router/reference/data-apis/query). - -## Behavior - -- `cache` and `query` reference the same function. -- Cache keys, reuse behavior, static methods, and revalidation behavior are the same as [`query`](/solid-router/reference/data-apis/query). - -## Examples - -### Basic usage - -```tsx -import { cache } from "@solidjs/router"; - -const getUser = cache(async (id: string) => { - const response = await fetch(`/api/users/${id}`); - return response.json(); -}, "user"); -``` - -## Related - -- [`query`](/solid-router/reference/data-apis/query) diff --git a/src/routes/solid-router/reference/data-apis/create-async-store.mdx b/src/routes/solid-router/reference/data-apis/create-async-store.mdx deleted file mode 100644 index 0c1962270..000000000 --- a/src/routes/solid-router/reference/data-apis/create-async-store.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: createAsyncStore -use_cases: >- - async stores, route data, reconciled data, nested data -tags: - - async - - stores - - data - - reconcile -version: "1.0" -description: >- - createAsyncStore creates an accessor for promise-backed store data. ---- - -`createAsyncStore` is a wrapper around `createResource` that tracks a promise-returning function and returns the resolved value through a store-backed accessor. - -## Import - -```tsx -import { createAsyncStore } from "@solidjs/router"; -``` - -## Type - -```tsx -function createAsyncStore<T>( - fn: (prev: T) => Promise<T>, - options: { - name?: string; - initialValue: T; - deferStream?: boolean; - reconcile?: ReconcileOptions; - } -): AccessorWithLatest<T>; - -function createAsyncStore<T>( - fn: (prev: T | undefined) => Promise<T>, - options?: { - name?: string; - initialValue?: T; - deferStream?: boolean; - reconcile?: ReconcileOptions; - } -): AccessorWithLatest<T | undefined>; -``` - -## Parameters - -### `fn` - -- **Type:** `(prev: T | undefined) => Promise<T>` -- **Required:** Yes - -Promise-returning function used as the async resource fetcher. -The resolved value is stored in the returned store-backed accessor. -Synchronous reactive reads made while `fn` runs are tracked, causing the resource to rerun when those dependencies change. - -### `options` - -- **Type:** `{ name?: string; initialValue?: T; deferStream?: boolean; reconcile?: ReconcileOptions }` -- **Default:** `{}` -- **Required:** No - -Options for the resource name, initial store value, server streaming, and store reconciliation. - -#### `name` - -- **Type:** `string` -- **Required:** No - -Name used by the resource for development debugging. - -#### `initialValue` - -- **Type:** `T` -- **Required:** No - -Initial store value returned by the accessor before the async function resolves. - -#### `deferStream` - -- **Type:** `boolean` -- **Default:** `false` -- **Required:** No - -If `true`, [streaming](/solid-router/data-fetching/streaming) waits for this resource to resolve before flushing. - -#### `reconcile` - -- **Type:** `ReconcileOptions` -- **Required:** No - -Options passed to [`reconcile`](/reference/store-utilities/reconcile). -These options control how resolved values are merged into the existing store. - -## Return value - -- **Type:** `AccessorWithLatest<T | undefined>` - -Returns an accessor for the resolved store value. -Before the first resolution, the accessor returns `initialValue` when provided and `undefined` otherwise. - -### `latest` - -- **Type:** `T | undefined` - -Getter that reads the `latest` value from the `createResource` result. - -## Behavior - -- Calls `createResource` with store-backed storage created by `createStore`. -- `fn` receives `unwrap(resource.latest)` when the resource has resolved, or `undefined` while unresolved. -- Initial store storage is created from `structuredClone(initialValue)`. -- Resolved values are cloned with `structuredClone` and merged with `reconcile`. -- The `reconcile` option is passed to [`reconcile`](/reference/store-utilities/reconcile) when store writes run. -- The returned accessor reads the current store-backed resource value. -- During hydration, `window.fetch` and `Promise` are temporarily replaced with mock implementations while `fn` runs. - -## Examples - -### With reactive arguments - -```tsx -import { For, createSignal } from "solid-js"; -import { createAsyncStore, query } from "@solidjs/router"; - -type Notification = { - id: string; - message: string; - user: { name: string }; -}; - -const getNotifications = query(async (unreadOnly: boolean) => { - const response = await fetch(`/api/notifications?unread=${unreadOnly}`); - return response.json() as Promise<Notification[]>; -}, "notifications"); - -function Notifications() { - const [unreadOnly, setUnreadOnly] = createSignal(false); - const notifications = createAsyncStore(() => getNotifications(unreadOnly()), { - initialValue: [], - }); - - return ( - <> - <button onClick={() => setUnreadOnly((value) => !value)}> - Toggle unread - </button> - <ul> - <For each={notifications()}> - {(notification) => ( - <li> - <div>{notification.message}</div> - <div>{notification.user.name}</div> - </li> - )} - </For> - </ul> - </> - ); -} -``` - -## Related - -- [`createAsync`](/solid-router/reference/data-apis/create-async) -- [`reconcile`](/reference/store-utilities/reconcile) diff --git a/src/routes/solid-router/reference/data-apis/create-async.mdx b/src/routes/solid-router/reference/data-apis/create-async.mdx deleted file mode 100644 index 1c827c0ba..000000000 --- a/src/routes/solid-router/reference/data-apis/create-async.mdx +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: createAsync -use_cases: >- - async data, resources, suspense, route data -tags: - - async - - data - - resource - - suspense -version: "1.0" -description: >- - createAsync creates an accessor for promise-backed data. ---- - -`createAsync` is a wrapper around `createResource` that tracks a promise-returning function and returns the resolved value through an accessor with a `latest` property. - -## Import - -```tsx -import { createAsync } from "@solidjs/router"; -``` - -## Type - -```tsx -type AccessorWithLatest<T> = { - (): T; - latest: T; -}; - -function createAsync<T>( - fn: (prev: T) => Promise<T>, - options: { - name?: string; - initialValue: T; - deferStream?: boolean; - } -): AccessorWithLatest<T>; - -function createAsync<T>( - fn: (prev: T | undefined) => Promise<T>, - options?: { - name?: string; - initialValue?: T; - deferStream?: boolean; - } -): AccessorWithLatest<T | undefined>; -``` - -## Parameters - -### `fn` - -- **Type:** `(prev: T | undefined) => Promise<T>` -- **Required:** Yes - -Promise-returning function used as the async resource fetcher. -The resolved value is returned by the accessor. -Synchronous reactive reads made while `fn` runs are tracked, causing the resource to rerun when those dependencies change. - -### `options` - -- **Type:** `{ name?: string; initialValue?: T; deferStream?: boolean }` -- **Required:** No - -Options for the resource name, initial value, and server streaming. - -#### `name` - -- **Type:** `string` -- **Required:** No - -Name used by the resource for development debugging. - -#### `initialValue` - -- **Type:** `T` -- **Required:** No - -Initial value returned by the accessor before the async function resolves. - -#### `deferStream` - -- **Type:** `boolean` -- **Default:** `false` -- **Required:** No - -When `true`, [streaming](/solid-router/data-fetching/streaming) waits for this resource to resolve before flushing. - -## Return value - -- **Type:** `AccessorWithLatest<T | undefined>` - -Returns an accessor for the resolved value. -Before the first resolution, the accessor returns `initialValue` when provided and `undefined` otherwise. - -### `latest` - -- **Type:** `T | undefined` - -Getter that reads the `latest` value from the `createResource` result. - -## Behavior - -- Calls `createResource` internally. -- `fn` receives the previous latest value when the resource has resolved, or `undefined` while unresolved. -- The previous-value read is wrapped in `untrack`. -- The returned accessor reads the current resource value, and `latest` reads `resource.latest`. -- During hydration, `window.fetch` and `Promise` are temporarily replaced with mock implementations while `fn` runs. - -## Examples - -### Basic usage - -```tsx -import { createAsync, query } from "@solidjs/router"; - -const getCurrentUser = query(async () => { - const response = await fetch("/api/current-user"); - return response.json() as Promise<{ name: string }>; -}, "currentUser"); - -function UserProfile() { - const user = createAsync(() => getCurrentUser()); - - return <div>{user()?.name}</div>; -} -``` - -### With parameter - -```tsx -import { createAsync, query } from "@solidjs/router"; - -type Invoice = { - number: string; - total: number; -}; - -const getInvoice = query(async (invoiceId: string) => { - const response = await fetch(`/api/invoices/${invoiceId}`); - return response.json() as Promise<Invoice>; -}, "invoice"); - -function InvoiceDetails(props: { invoiceId: string }) { - const invoice = createAsync(() => getInvoice(props.invoiceId)); - - return ( - <div> - <h2>Invoice #{invoice()?.number}</h2> - <p>Total: ${invoice()?.total}</p> - </div> - ); -} -``` - -### With Suspense and ErrorBoundary - -```tsx -import { ErrorBoundary, For, Suspense } from "solid-js"; -import { createAsync, query } from "@solidjs/router"; - -type Recipe = { - name: string; - time: string; -}; - -const getRecipes = query(async () => { - const response = await fetch("/api/recipes"); - return response.json() as Promise<Recipe[]>; -}, "recipes"); - -function Recipes() { - const recipes = createAsync(() => getRecipes()); - - return ( - <ErrorBoundary fallback={<p>Couldn't fetch any recipes.</p>}> - <Suspense fallback={<p>Fetching recipes...</p>}> - <For each={recipes()}> - {(recipe) => ( - <div> - <h3>{recipe.name}</h3> - <p>Cook time: {recipe.time}</p> - </div> - )} - </For> - </Suspense> - </ErrorBoundary> - ); -} -``` - -## Related - -- [`query`](/solid-router/reference/data-apis/query) -- [`createAsyncStore`](/solid-router/reference/data-apis/create-async-store) -- [`<Suspense>`](/reference/components/suspense) -- [`<ErrorBoundary>`](/reference/components/error-boundary) diff --git a/src/routes/solid-router/reference/data-apis/query.mdx b/src/routes/solid-router/reference/data-apis/query.mdx deleted file mode 100644 index e92b8be40..000000000 --- a/src/routes/solid-router/reference/data-apis/query.mdx +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: query -use_cases: >- - data queries, cache keys, route data, revalidation -tags: - - query - - cache - - data - - revalidation -version: "1.0" -description: >- - query wraps a function with router cache metadata. ---- - -`query` caches the result of a function call by name and arguments. -Calls with the same name and serialized arguments share the same cache entry. - -## Import - -```tsx -import { query } from "@solidjs/router"; -``` - -## Type - -```tsx -type CachedFunction<T extends (...args: any) => any> = T extends ( - ...args: infer A -) => infer R - ? (( - ...args: A - ) => R extends Promise<infer P> - ? Promise<NarrowResponse<P>> - : NarrowResponse<R>) & { - keyFor: (...args: A) => string; - key: string; - } - : never; - -function query<T extends (...args: any) => any>( - fn: T, - name: string -): CachedFunction<T>; - -namespace query { - function get(key: string): any; - function set<T>( - key: string, - value: T extends Promise<any> ? never : T - ): void; - function delete(key: string): boolean; - function clear(): void; -} -``` - -## Parameters - -### `fn` - -- **Type:** `T extends (...args: any) => any` -- **Required:** Yes - -Function whose result is cached. -Arguments passed to the wrapped function are included in the cache key. -Arguments should serialize consistently with `JSON.stringify`. - -### `name` - -- **Type:** `string` -- **Required:** Yes - -Base key combined with the serialized argument list. -Functions with the same `name` and serialized arguments share a cache entry. - -## Return value - -`query` returns a function with the same call signature as `fn`. -The returned function has the following properties: - -### `key` - -- **Type:** `string` - -Base key for the query. - -### `keyFor` - -- **Type:** `(...args: Parameters<T>) => string` - -Returns the cache key for a specific argument list. - -## Static methods - -The `query` namespace has methods for reading and mutating the active cache. -Pass a cache key from a query function's `key` or `keyFor` property. - -### `get` - -- **Type:** `(key: string) => any` - -Returns the resolved value for an existing cache entry. - -### `set` - -- **Type:** `<T>(key: string, value: T extends Promise<any> ? never : T) => void` - -Stores a resolved, non-promise value for `key`. - -### `delete` - -- **Type:** `(key: string) => boolean` - -Deletes the cache entry for `key`. - -### `clear` - -- **Type:** `() => void` - -Clears the active cache. - -## Behavior - -### Cache keys - -- Cache keys are built from `name` plus the serialized argument list. -- Argument serialization uses `JSON.stringify` and sorts keys for plain objects. -- When `fn` has a `GET` property, `fn.GET` is wrapped. - -### Cache reuse - -- Preloaded route data is reused for `5000` milliseconds when a later call has the same cache key. -- Active subscriptions keep matching cache entries reusable while subscribed. -- Native history navigation reuses matching cache entries instead of calling `fn` again. -- During server rendering, repeated calls with the same cache key reuse the same request-scoped cache entry. -- During hydration, a matching serialized value from Solid's shared config is loaded instead of calling `fn`. - -### Cache storage - -- During server rendering, cache entries are stored on the request event router cache. -- On the client, cache entries are stored in a module-level map. -- Client cache entries with no active subscribers can be deleted after `180000` milliseconds. -- Static methods read or mutate the active cache. - -### Response handling - -- Returned `Response` headers are copied to the request event response during server rendering. -- Returned `Response` objects with a `Location` header trigger navigation on the client or set a `302` response status during server rendering. - -## Examples - -### Basic usage - -```tsx -import { query } from "@solidjs/router"; - -const getUserProfile = query(async (userId: string) => { - const response = await fetch(`/api/users/${encodeURIComponent(userId)}`); - const json = await response.json(); - - if (!response.ok) { - throw new Error(json?.message ?? "Failed to load user profile."); - } - - return json as { name: string }; -}, "userProfile"); - -const key = getUserProfile.keyFor("123"); -``` - -### Reading and writing cache entries - -```tsx -const key = getUserProfile.keyFor("123"); - -query.set(key, { name: "Ada" }); -const cached = query.get(key); - -query.delete(key); -``` - -## Related - -- [`createAsync`](/solid-router/reference/data-apis/create-async) -- [`revalidate`](/solid-router/reference/data-apis/revalidate) diff --git a/src/routes/solid-router/reference/data-apis/revalidate.mdx b/src/routes/solid-router/reference/data-apis/revalidate.mdx deleted file mode 100644 index 95e6b93ce..000000000 --- a/src/routes/solid-router/reference/data-apis/revalidate.mdx +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: revalidate -use_cases: >- - query revalidation, cache invalidation, data refresh -tags: - - revalidate - - cache - - query -version: "1.0" -description: >- - revalidate retriggers router query cache entries. ---- - -`revalidate` retriggers [`query`](/solid-router/reference/data-apis/query) cache entries inside a transition. - -## Import - -```tsx -import { revalidate } from "@solidjs/router"; -``` - -## Type - -```tsx -function revalidate( - key?: string | string[] | void, - force?: boolean -): Promise<void>; -``` - -## Parameters - -### `key` - -- **Type:** `string | string[] | void` -- **Required:** No - -Cache key or keys from a query function's [`key`](/solid-router/reference/data-apis/query#key) or [`keyFor`](/solid-router/reference/data-apis/query#keyfor) property. - -### `force` - -- **Type:** `boolean` -- **Default:** `true` -- **Required:** No - -When `true`, matching cache entries are marked as cache misses before subscribers are retriggered. -When `false`, subscribers are retriggered without changing cache entry timestamps. - -## Return value - -- **Type:** `Promise<void>` - -Resolves when the revalidation transition completes. - -## Behavior - -- Runs inside [`startTransition`](/reference/reactive-utilities/start-transition). -- When `key` is undefined, every cache entry matches. -- A string or array `key` matches cache entries by key prefix. [`query.key`](/solid-router/reference/data-apis/query#key) targets every cached argument set for that query; [`query.keyFor(...)`](/solid-router/reference/data-apis/query#keyfor) targets one serialized argument list. -- Matching cache entries update their live signal with the current timestamp, retriggering active cache reads through primitives such as [`createAsync`](/solid-router/reference/data-apis/create-async). -- Without active subscribers, `revalidate` does not call the query function. - -## Examples - -### Basic usage - -```tsx -import { For } from "solid-js"; -import { createAsync, query, revalidate } from "@solidjs/router"; - -const getTodos = query(async () => { - const response = await fetch("/api/todos"); - return response.json() as Promise<{ id: string; title: string }[]>; -}, "todos"); - -function Todos() { - const todos = createAsync(() => getTodos(), { initialValue: [] }); - - function refreshTodos() { - void revalidate(getTodos.key); - } - - return ( - <> - <button onClick={refreshTodos}>Refresh todos</button> - <ul> - <For each={todos()}>{(todo) => <li>{todo.title}</li>}</For> - </ul> - </> - ); -} -``` - -### Revalidate a query argument - -```tsx -import { createAsync, query, revalidate } from "@solidjs/router"; - -const getProjectTasks = query(async (projectId: string) => { - const response = await fetch(`/api/projects/${projectId}/tasks`); - return response.json() as Promise<{ id: string; title: string }[]>; -}, "projectTasks"); - -function ProjectTasks(props: { projectId: string }) { - const tasks = createAsync(() => getProjectTasks(props.projectId), { - initialValue: [], - }); - - function refreshProjectTasks() { - void revalidate(getProjectTasks.keyFor(props.projectId)); - } - - return ( - <> - <button onClick={refreshProjectTasks}>Refresh project tasks</button> - <div>{tasks().length} tasks</div> - </> - ); -} -``` - -## Related - -- [`query`](/solid-router/reference/data-apis/query) -- [`createAsync`](/solid-router/reference/data-apis/create-async) -- [`reload`](/solid-router/reference/response-helpers/reload) diff --git a/src/routes/solid-router/reference/data-apis/use-action.mdx b/src/routes/solid-router/reference/data-apis/use-action.mdx deleted file mode 100644 index 1f47dd4f4..000000000 --- a/src/routes/solid-router/reference/data-apis/use-action.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: useAction -use_cases: >- - actions, programmatic actions, mutations -tags: - - actions - - mutations - - programmatic -version: "1.0" -description: >- - useAction returns a router-bound action caller. ---- - -`useAction` returns a function that calls an [`action`](/solid-router/reference/data-apis/action) with the current router context. It is the programmatic caller for non-form submissions. - -## Import - -```tsx -import { useAction } from "@solidjs/router"; -``` - -## Type - -```tsx -function useAction<T extends Array<any>, U, V>( - action: Action<T, U, V> -): (...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>; -``` - -## Parameters - -### `action` - -- **Type:** `Action<T, U, V>` -- **Required:** Yes - -[`Action`](/solid-router/reference/data-apis/action) to bind to the current router. - -## Return value - -- **Type:** `(...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>` - -Returns a router-bound caller with the same arguments as `action`. - -## Behavior - -- Unlike native form submissions, calls made with `useAction` depend on client-side JavaScript. - -## Examples - -### Basic usage - -```tsx -import { action, useAction } from "@solidjs/router"; - -const likePost = action(async (id: string) => { - return id; -}, "likePost"); - -function LikeButton(props: { id: string }) { - const like = useAction(likePost); - - return <button onClick={() => like(props.id)}>Like</button>; -} -``` - -## Related - -- [`action`](/solid-router/reference/data-apis/action) diff --git a/src/routes/solid-router/reference/data-apis/use-submission.mdx b/src/routes/solid-router/reference/data-apis/use-submission.mdx deleted file mode 100644 index 9da225e5f..000000000 --- a/src/routes/solid-router/reference/data-apis/use-submission.mdx +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: useSubmission -use_cases: >- - latest submission, action submission, pending action -tags: - - submission - - actions - - pending -version: "1.0" -description: >- - useSubmission returns the latest tracked submission for an action. ---- - -`useSubmission` returns a proxy for the latest submission created by a matching [`action`](/solid-router/reference/data-apis/action). - -## Import - -```tsx -import { useSubmission } from "@solidjs/router"; -``` - -## Type - -```tsx -function useSubmission<T extends Array<any>, U, V>( - fn: Action<T, U, V>, - filter?: (input: V) => boolean -): Submission<T, NarrowResponse<U>> | SubmissionStub; -``` - -## Parameters - -### `fn` - -- **Type:** `Action<T, U, V>` -- **Required:** Yes - -[`Action`](/solid-router/reference/data-apis/action) whose latest submission is returned. - -### `filter` - -- **Type:** `(input: V) => boolean` -- **Required:** No - -Function used to filter submissions by input. - -## Return value - -`useSubmission` returns an object with the latest matching submission fields: - -### `input` - -- **Type:** `T | undefined` - -Input passed to the action. - -### `result` - -- **Type:** `NarrowResponse<U> | undefined` - -Value returned by the action. - -### `error` - -- **Type:** `any` - -Error thrown or rejected by the action. - -### `url` - -- **Type:** `string | undefined` - -URL used to match the action. - -### `pending` - -- **Type:** `boolean | undefined` - -Whether the submission is still running. - -### `clear` - -- **Type:** `() => void` - -Function that clears the latest submission when one exists. - -### `retry` - -- **Type:** `() => void` - -No-op function on the returned proxy. - -## Behavior - -- Uses [`useSubmissions`](/solid-router/reference/data-apis/use-submissions) and reads the last matching submission. -- If there are no matching submissions, `clear` returns a no-op function. -- `retry` is always a no-op on the returned proxy. -- Other fields return data from the latest match, or `undefined` when there is no matching submission. - -## Examples - -### Basic usage - -```tsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const addTodo = action(async (data: URLSearchParams) => { - return data.get("title")?.toString(); -}, "addTodo"); - -function TodoForm() { - const submission = useSubmission(addTodo); - - return ( - <form action={addTodo} method="post"> - <input name="title" /> - <button>Add todo</button> - <Show when={submission.pending}>Saving...</Show> - </form> - ); -} -``` - -## Related - -- [`action`](/solid-router/reference/data-apis/action) -- [`useSubmissions`](/solid-router/reference/data-apis/use-submissions) diff --git a/src/routes/solid-router/reference/data-apis/use-submissions.mdx b/src/routes/solid-router/reference/data-apis/use-submissions.mdx deleted file mode 100644 index f8c6144f3..000000000 --- a/src/routes/solid-router/reference/data-apis/use-submissions.mdx +++ /dev/null @@ -1,191 +0,0 @@ ---- -title: useSubmissions -use_cases: >- - action submissions, submission arrays, pending actions -tags: - - submissions - - actions - - pending -version: "1.0" -description: >- - useSubmissions returns tracked submissions for an action. ---- - -`useSubmissions` returns a reactive array-like proxy for submissions created by a matching action. - -## Import - -```tsx -import { useSubmissions } from "@solidjs/router"; -``` - -## Type - -```tsx -type Submission<T, U> = { - readonly input: T; - readonly result?: U; - readonly error: any; - readonly pending: boolean; - readonly url: string; - clear: () => void; - retry: () => void; -}; - -function useSubmissions<T extends Array<any>, U, V>( - fn: Action<T, U, V>, - filter?: (input: V) => boolean -): Submission<T, NarrowResponse<U>>[] & { pending: boolean }; -``` - -## Parameters - -### `fn` - -- **Type:** `Action<T, U, V>` -- **Required:** Yes - -Action whose submissions are returned. - -### `filter` - -- **Type:** `(input: V) => boolean` -- **Required:** No - -Function that receives each submission input. -Records are included when it returns `true`. - -## Return value - -`useSubmissions` returns an array-like object of submissions with an additional `pending` property. - -### `pending` - -- **Type:** `boolean` - -`true` when at least one matching submission has no result value. - -### Submission records - -#### `input` - -- **Type:** `T` - -Arguments from the original call. - -#### `result` - -- **Type:** `NarrowResponse<U> | undefined` - -Value returned by the action. - -#### `error` - -- **Type:** `any` - -Error thrown or rejected by the action. - -#### `url` - -- **Type:** `string` - -URL used to match the record to its action. - -#### `clear` - -- **Type:** `() => void` - -Function that removes the record. - -#### `retry` - -- **Type:** `() => void` - -Function that runs the same call again. - -## Behavior - -- Filters router submissions by action URL. -- When `filter` is provided, only submissions whose input passes the filter are returned. -- The returned value is a proxy over the filtered submissions. - -## Examples - -### Basic usage - -```tsx -import { For, Show } from "solid-js"; -import { action, useSubmissions } from "@solidjs/router"; - -const addTodoAction = action(async (formData: FormData) => { - // ... Sends the todo data to the server. -}, "addTodo"); - -function AddTodoForm() { - const submissions = useSubmissions(addTodoAction); - - return ( - <div> - <form action={addTodoAction} method="post"> - <input name="name" /> - <button type="submit">Add</button> - </form> - <For each={submissions}> - {(submission) => ( - <div> - <span>Adding "{submission.input[0].get("name")?.toString()}"</span> - <Show when={submission.pending}> - <span> (pending...)</span> - </Show> - <Show when={submission.result?.ok}> - <span> (completed)</span> - </Show> - <Show when={!submission.result?.ok}> - <span>{` (Error: ${submission.result?.message})`}</span> - <button onClick={() => submission.retry()}>Retry</button> - </Show> - </div> - )} - </For> - </div> - ); -} -``` - -### Filtering submissions - -```tsx -import { useSubmissions } from "@solidjs/router"; - -const addTodoAction = action(async (formData: FormData) => { - // ... Sends the todo data to the server. -}, "addTodo"); - -function FailedTodos() { - const failedSubmissions = useSubmissions( - addTodoAction, - ([formData]: [FormData]) => { - // Filters for submissions that failed a client-side validation - const name = formData.get("name")?.toString() ?? ""; - return name.length <= 2; - } - ); - - return ( - <div> - <p>Failed submissions:</p> - <For each={failedSubmissions}> - {(submission) => ( - <div> - <span>{submission.input[0].get("name")?.toString()}</span> - <button onClick={() => submission.retry()}>Retry</button> - </div> - )} - </For> - </div> - ); -} -``` - -- [`action`](/solid-router/reference/data-apis/action) -- [`useSubmission`](/solid-router/reference/data-apis/use-submission) diff --git a/src/routes/solid-router/reference/preload-functions/preload.mdx b/src/routes/solid-router/reference/preload-functions/preload.mdx deleted file mode 100644 index 780b99312..000000000 --- a/src/routes/solid-router/reference/preload-functions/preload.mdx +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: preload -use_cases: >- - route preload, route data, route definitions -tags: - - preload - - routing - - data -version: "1.0" -description: >- - preload is a route definition property for route data setup. ---- - -`preload` is a [`Route`](/solid-router/reference/components/route) property for preparing route data before the route component renders or while a route is being preloaded. - -## Import - -```tsx -import { Route } from "@solidjs/router"; -``` - -## Type - -```tsx -type Intent = "initial" | "native" | "navigate" | "preload"; - -interface RoutePreloadFuncArgs { - params: Params; - location: Location; - intent: Intent; -} - -type RoutePreloadFunc<T = unknown> = (args: RoutePreloadFuncArgs) => T; -``` - -## Parameters - -### `params` - -- **Type:** `Params` -- **Required:** Yes - -Route params for the matched route. -The value has the same shape as [`useParams`](/solid-router/reference/primitives/use-params). - -### `location` - -- **Type:** `Location` -- **Required:** Yes - -[`Location`](/solid-router/reference/primitives/use-location) for the route being loaded or preloaded. - -### `intent` - -- **Type:** `"initial" | "native" | "navigate" | "preload"` -- **Required:** Yes - -Reason the router called the preload function, such as initial render, router navigation, native history navigation, or route preloading. - -## Return value - -- **Type:** `T` - -Returns the route data value. -During route context creation, Solid Router passes this value to the matched route component as `props.data`. - -## Behavior - -- During route context creation, Solid Router calls `preload` with the matched params, current location, and current router intent or `"initial"`. -- Manual route preloading calls `preload` with `intent: "preload"` only when `preloadData` is truthy. -- If a route definition has no `preload`, Solid Router uses the deprecated `load` property when one is present. -- The route component's static `preload` method runs before the route-level `preload` function. - -## Examples - -### Basic usage - -```tsx -import { Route, query } from "@solidjs/router"; - -const getProduct = query(async (id: string) => { - const response = await fetch(`/api/products/${id}`); - return response.json(); -}, "product"); - -function preloadProduct({ params }) { - void getProduct(params.id); -} - -function ProductPage(props) { - return <h1>Product {props.params.id}</h1>; -} - -export default function ProductRoutes() { - return ( - <Route - path="/products/:id" - component={ProductPage} - preload={preloadProduct} - /> - ); -} -``` - -## Related - -- [`Route`](/solid-router/reference/components/route) -- [`usePreloadRoute`](/solid-router/reference/primitives/use-preload-route) diff --git a/src/routes/solid-router/reference/primitives/use-before-leave.mdx b/src/routes/solid-router/reference/primitives/use-before-leave.mdx deleted file mode 100644 index 245cdebcc..000000000 --- a/src/routes/solid-router/reference/primitives/use-before-leave.mdx +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: useBeforeLeave -use_cases: >- - navigation blocking, leave handlers, unsaved changes -tags: - - navigation - - lifecycle - - prevent - - route -version: "1.0" -description: >- - useBeforeLeave registers a handler that runs before navigation leaves the current location. ---- - -`useBeforeLeave` registers a listener that will be called prior to leaving the current location. - -## Import - -```ts -import { useBeforeLeave } from "@solidjs/router"; -``` - -## Type - -```ts -interface BeforeLeaveEventArgs { - from: Location; - to: string | number; - options?: Partial<NavigateOptions>; - readonly defaultPrevented: boolean; - preventDefault(): void; - retry(force?: boolean): void; -} - -function useBeforeLeave(listener: (event: BeforeLeaveEventArgs) => void): void; -``` - -## Parameters - -### `listener` - -- **Type:** `(event: BeforeLeaveEventArgs) => void` -- **Required:** Yes - -Function called before navigation leaves the current location. - -The listener receives one argument with these fields and methods: - -| Name | Type | Default | Description | -| ------------------ | --------------------------------------- | ----------- | ------------------------------------------------------------------------------- | -| `from` | `Location` | N/A | Current location before the change. | -| `to` | `string \| number` | N/A | Target passed to `navigate`. | -| `options` | `Partial<NavigateOptions> \| undefined` | `undefined` | Options passed to `navigate`. | -| `preventDefault` | `() => void` | N/A | Blocks the route change. | -| `defaultPrevented` | `readonly boolean` | `false` | `true` after this handler or an earlier leave handler calls `preventDefault()`. | -| `retry` | `(force?: boolean) => void` | N/A | Retries the same navigation. Pass `true` to skip running leave handlers again. | - -## Return value - -- **Type:** `void` - -`useBeforeLeave` does not return a value. - -## Behavior - -- The subscription is tied to the current owner and is removed during cleanup. -- The event contains the current location in `from`, the next target in `to`, and navigation options in `options`. -- Calling `event.preventDefault()` sets `event.defaultPrevented` and blocks the current navigation. -- Calling `event.retry(true)` retries the same navigation and skips the before-leave lifecycle for that retry. - -## Examples - -### Basic usage - -```tsx -import { useBeforeLeave } from "@solidjs/router"; - -function Editor(props: { isDirty: () => boolean }) { - useBeforeLeave((event) => { - if (props.isDirty() && !event.defaultPrevented) { - event.preventDefault(); - } - }); - - return <form>{/* fields */}</form>; -} -``` - -## Related - -- [`useNavigate`](/solid-router/reference/primitives/use-navigate) -- [`Router`](/solid-router/reference/components/router) diff --git a/src/routes/solid-router/reference/primitives/use-current-matches.mdx b/src/routes/solid-router/reference/primitives/use-current-matches.mdx deleted file mode 100644 index 9447fd889..000000000 --- a/src/routes/solid-router/reference/primitives/use-current-matches.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: useCurrentMatches -use_cases: >- - current matches, route metadata, nested route matches -tags: - - routes - - matches - - metadata -version: "1.0" -description: >- - useCurrentMatches returns the current route matches accessor. ---- - -`useCurrentMatches` returns the route matches for the current location. - -## Import - -```ts -import { useCurrentMatches } from "@solidjs/router"; -``` - -## Type - -```ts -interface RouteMatch extends PathMatch { - route: RouteDescription; -} - -function useCurrentMatches(): () => RouteMatch[]; -``` - -## Parameters - -`useCurrentMatches` takes no arguments. - -## Return value - -- **Type:** `() => RouteMatch[]` - -Returns the route matches accessor. - -## Behavior - -- Matches are computed from route branches and the current pathname, after applying `transformUrl` when configured. -- The accessor updates when the current location changes. - -## Examples - -### Basic usage - -```tsx -import { createMemo } from "solid-js"; -import { useCurrentMatches } from "@solidjs/router"; - -function Breadcrumbs() { - const matches = useCurrentMatches(); - const breadcrumbs = createMemo(() => - matches().map((match) => match.route.info?.breadcrumb) - ); - - return <>{breadcrumbs().join(" / ")}</>; -} -``` - -## Related - -- [`Route`](/solid-router/reference/components/route) -- [`useMatch`](/solid-router/reference/primitives/use-match) diff --git a/src/routes/solid-router/reference/primitives/use-is-routing.mdx b/src/routes/solid-router/reference/primitives/use-is-routing.mdx deleted file mode 100644 index ecf6612f3..000000000 --- a/src/routes/solid-router/reference/primitives/use-is-routing.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: useIsRouting -use_cases: >- - route transitions, pending routing state, navigation state -tags: - - routing - - transition - - pending - - state -version: "1.0" -description: >- - useIsRouting detects when a route transition is in progress. ---- - -`useIsRouting` returns an accessor for whether a route transition is in progress. - -## Import - -```ts -import { useIsRouting } from "@solidjs/router"; -``` - -## Type - -```ts -function useIsRouting(): () => boolean; -``` - -## Parameters - -`useIsRouting` takes no arguments. - -## Return value - -- **Type:** `() => boolean` - -Returns an accessor that reads the current route transition state. - -## Behavior - -- The accessor becomes `true` when a transition target starts and `false` after the active transition finishes. - -## Examples - -### Basic usage - -```tsx -import { Show } from "solid-js"; -import { useIsRouting } from "@solidjs/router"; - -function PendingRoute() { - const isRouting = useIsRouting(); - - return <Show when={isRouting()}>Loading route...</Show>; -} -``` - -## Related - -- [`Router`](/solid-router/reference/components/router) -- [`useNavigate`](/solid-router/reference/primitives/use-navigate) diff --git a/src/routes/solid-router/reference/primitives/use-location.mdx b/src/routes/solid-router/reference/primitives/use-location.mdx deleted file mode 100644 index 8f5e85219..000000000 --- a/src/routes/solid-router/reference/primitives/use-location.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: useLocation -use_cases: >- - current url, pathname, query parameters, hash, navigation state -tags: - - location - - url - - pathname - - query - - state -version: "1.0" -description: >- - useLocation returns the current location. ---- - -`useLocation` returns the current location object. - -## Import - -```ts -import { useLocation } from "@solidjs/router"; -``` - -## Type - -```ts -function useLocation<S = unknown>(): Location<S>; - -interface Location<S = unknown> extends Path { - query: SearchParams; - state: Readonly<Partial<S>> | null; - key: string; -} - -interface Path { - pathname: string; - search: string; - hash: string; -} -``` - -## Parameters - -`useLocation` takes no arguments. - -## Return value - -`useLocation` returns an object with the following properties: - -### `pathname` - -- **Type:** `string` - -Current URL pathname. - -### `search` - -- **Type:** `string` - -Current URL search string. - -### `hash` - -- **Type:** `string` - -The hash fragment of the URL, including the leading `#` character if a hash exists. - -### `query` - -- **Type:** `SearchParams` - -A reactive object containing the parsed query parameters from the URL. - -### `state` - -- **Type:** `Readonly<Partial<S>> | null` - -Custom state passed from [`useNavigate`](/solid-router/reference/primitives/use-navigate). - -### `key` - -- **Type:** `string` - -Location key. - -## Behavior - -- The location object updates when location state changes. -- The `query` object is derived from `search`. - -## Examples - -### Basic usage - -```tsx -import { useLocation } from "@solidjs/router"; - -function ProductFilter() { - const location = useLocation(); - - const category = () => location.query.category || "all"; - const page = () => location.query.page || "1"; - - return ( - <div> - <p> - Filtering by: {category()}, Page {page()} - </p> - </div> - ); -} -``` - -## Related - -- [`useNavigate`](/solid-router/reference/primitives/use-navigate) -- [`useParams`](/solid-router/reference/primitives/use-params) -- [`useSearchParams`](/solid-router/reference/primitives/use-search-params) diff --git a/src/routes/solid-router/reference/primitives/use-match.mdx b/src/routes/solid-router/reference/primitives/use-match.mdx deleted file mode 100644 index a174633c0..000000000 --- a/src/routes/solid-router/reference/primitives/use-match.mdx +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: useMatch -use_cases: >- - path matching, active states, route matching -tags: - - match - - path - - routes -version: "1.0" -description: >- - useMatch returns a memoized match for a path pattern. ---- - -`useMatch` returns an accessor for matching the current pathname against a route pattern. - -## Import - -```ts -import { useMatch } from "@solidjs/router"; -``` - -## Type - -```ts -type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean); - -type MatchFilters<P extends string | readonly string[] = any> = P extends string - ? { [K in PathParams<P>[number]]?: MatchFilter } - : Record<string, MatchFilter>; - -interface PathMatch { - params: Params; - path: string; -} - -function useMatch<S extends string>( - path: () => S, - matchFilters?: MatchFilters<S> -): Accessor<PathMatch | undefined>; -``` - -## Parameters - -### `path` - -- **Type:** `() => S` -- **Required:** Yes - -Accessor that returns the path pattern to match. - -### `matchFilters` - -- **Type:** `MatchFilters<S>` -- **Required:** No - -Filters applied to path parameters in the pattern. -Each filter can be: - -- An array of allowed strings -- A regular expression pattern -- A function that receives the parameter value as a string and returns true if the parameter should match - -## Return value - -`useMatch` returns a memo containing a `PathMatch` object when the path matches, or `undefined` when there's no match. - -The `PathMatch` object contains: - -### `params` - -- **Type:** `Record<string, string>` - -An object containing the matched path parameters as key-value pairs. - -### `path` - -- **Type:** `string` - -The matched path. - -## Behavior - -- Expands optional path segments before creating matchers. -- Matchers test against [`useLocation`](/solid-router/reference/primitives/use-location)'s `pathname`. -- The accessor returns the first match or `undefined`. - -## Examples - -### Basic usage - -```tsx -import { useMatch } from "@solidjs/router"; -import { type JSXElement } from "solid-js"; - -type NavLinkProps = { - href: string; - children: JSXElement; -}; - -function NavLink(props: NavLinkProps) { - const match = useMatch(() => props.href); - - return ( - <a href={props.href} classList={{ active: Boolean(match()) }}> - {props.children} - </a> - ); -} -``` - -### With filters - -```tsx -import { useMatch } from "@solidjs/router"; -import { Show } from "solid-js"; - -function BlogPost() { - const match = useMatch(() => "/:lang?/blog/:slug", { - lang: ["en", "es", "fr"], - slug: /^[a-z0-9-]+$/, // Only allow lowercase letters, numbers, and hyphens - }); - - const lang = () => match()?.params.lang || "en"; - - return ( - <Show when={match()}> - <article lang={lang()}> - <p>Blog slug: {match()?.params.slug}</p> - </article> - </Show> - ); -} -``` - -### With custom filter functions - -```tsx -import { useMatch } from "@solidjs/router"; - -function FileInfo() { - const match = useMatch(() => "/files/:type/:name", { - type: ["images", "documents", "videos"], - name: (name) => name.length > 5 && name.endsWith(".html"), - }); - - return <div>File: {match()?.params.name}</div>; -} -``` - -## Related - -- [`useParams`](/solid-router/reference/primitives/use-params) -- [`useLocation`](/solid-router/reference/primitives/use-location) diff --git a/src/routes/solid-router/reference/primitives/use-navigate.mdx b/src/routes/solid-router/reference/primitives/use-navigate.mdx deleted file mode 100644 index 42f219dcc..000000000 --- a/src/routes/solid-router/reference/primitives/use-navigate.mdx +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: useNavigate -use_cases: >- - programmatic navigation, redirects, history navigation, navigation state -tags: - - navigate - - redirect - - history - - state -version: "1.0" -description: >- - useNavigate returns the navigation function. ---- - -`useNavigate` returns a function for programmatically navigating to a new route. - -## Import - -```ts -import { useNavigate } from "@solidjs/router"; -``` - -## Type - -```ts -interface NavigateOptions<S = unknown> { - resolve: boolean; - replace: boolean; - scroll: boolean; - state: S; -} - -interface Navigator { - (to: string | number, options?: Partial<NavigateOptions>): void; - (delta: number): void; -} - -function useNavigate(): Navigator; -``` - -## Parameters - -`useNavigate` takes no arguments. - -## Return value - -- **Type:** `Navigator` - -Returns a function that accepts two arguments: - -### `to` - -- **Type:** `string | number` -- **Required:** Yes - -Path to navigate to, or history delta (e.g., `-1` for back, `1` for forward) for the router integration. - -### `options` - -- **Type:** `Partial<NavigateOptions>` -- **Required:** No - -Navigation options used when `to` is a string. - -### `options.resolve` - -- **Type:** `boolean` -- **Default:** `true` for path navigation, `false` for query-only strings. - -Controls whether the target path resolves against the current route. - -### `options.replace` - -- **Type:** `boolean` -- **Default:** `false` - -Controls whether navigation replaces the current history entry. - -### `options.scroll` - -- **Type:** `boolean` -- **Default:** `true` - -Controls whether navigation scrolls after the route changes. - -### `options.state` - -- **Type:** `unknown` -- **Default:** `undefined` - -State stored with the next location. - -## Behavior - -- Passing `0` as a history delta does nothing. -- Nonzero history deltas call the router integration `go` function when one exists. -- Query-only strings are resolved against the current pathname. -- On the server, path navigation sets a `302` response with a `Location` header when a request event is available. - -## Examples - -### Basic usage - -```tsx -import { useNavigate } from "@solidjs/router"; - -const navigate = useNavigate(); - -navigate("/users/123"); -``` - -### With `replace` - -```tsx -import { useNavigate } from "@solidjs/router"; - -const navigate = useNavigate(); - -// Redirect (replace history) -function login() { - navigate("/dashboard", { replace: true }); -} -``` - -### With `delta` - -```tsx -import { useNavigate } from "@solidjs/router"; - -const navigate = useNavigate(); - -// Go back one page -function goBack() { - navigate(-1); -} -``` - -### With `state` - -```tsx -import { useNavigate } from "@solidjs/router"; - -const navigate = useNavigate(); - -// Pass custom state -navigate("/checkout", { - state: { from: "cart", total: 100 }, -}); -``` - -## Related - -- [useLocation](/solid-router/reference/primitives/use-location) -- [redirect](/solid-router/reference/response-helpers/redirect) diff --git a/src/routes/solid-router/reference/primitives/use-params.mdx b/src/routes/solid-router/reference/primitives/use-params.mdx deleted file mode 100644 index da54217d6..000000000 --- a/src/routes/solid-router/reference/primitives/use-params.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: useParams -use_cases: >- - route parameters, dynamic routes, path params -tags: - - params - - dynamic - - routes - - reactive -version: "1.0" -description: >- - useParams returns the current route parameters. ---- - -`useParams` returns the merged params for the current route matches. - -## Import - -```ts -import { useParams } from "@solidjs/router"; -``` - -## Type - -```ts -type Params = Record<string, string | undefined>; - -function useParams<T extends Params>(): T; -``` - -## Parameters - -`useParams` takes no arguments. - -## Return value - -- **Type:** `T` - -Returns a reactive object where keys match the dynamic segments defined in the route path. - -## Behavior - -- Route params are built by merging params from the current route matches. -- The default params object tracks property reads. -- Accessing a property within a tracking scope registers a dependency, causing the computation to re-run when the parameter changes. - -## Examples - -### Basic usage - -```ts -import { createMemo } from "solid-js"; -import { useParams } from "@solidjs/router"; - -// Rendered via <Route path="/users/:id" component={UserPage} /> -function UserPage() { - const params = useParams(); - - // Derived value updates when the route parameter changes. - const title = createMemo(() => `Profile for ${params.id}`); - - return <h1>{title()}</h1>; -} -``` - -## Related - -- [useLocation](/solid-router/reference/primitives/use-location) -- [useSearchParams](/solid-router/reference/primitives/use-search-params) diff --git a/src/routes/solid-router/reference/primitives/use-preload-route.mdx b/src/routes/solid-router/reference/primitives/use-preload-route.mdx deleted file mode 100644 index 6fc9106fa..000000000 --- a/src/routes/solid-router/reference/primitives/use-preload-route.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: usePreloadRoute -use_cases: >- - route preloading, manual preload, route data preload -tags: - - preload - - routing - - data -version: "1.0" -description: >- - usePreloadRoute returns a function for preloading a route. ---- - -`usePreloadRoute` returns a function for manually preloading a route. - -## Import - -```ts -import { usePreloadRoute } from "@solidjs/router"; -``` - -## Type - -```ts -function usePreloadRoute(): ( - url: string | URL, - options?: { preloadData?: boolean } -) => void; -``` - -## Parameters - -`usePreloadRoute` takes no arguments. - -## Return value - -- **Type:** `(url: string | URL, options?: { preloadData?: boolean }) => void` - -Returns a function that preloads the matching route for a URL. - -### `url` - -- **Type:** `string | URL` -- **Required:** Yes - -URL or URL string to preload. - -### `options` - -- **Type:** `{ preloadData?: boolean }` -- **Required:** No - -A configuration object with the following properties: - -#### `preloadData` - -- **Type:** `boolean` -- **Default:** `false` - -When `true`, triggers the route's data loading in addition to preloading the route itself. - -## Return value - -None. - -## Examples - -### Basic usage - -```tsx -import { usePreloadRoute } from "@solidjs/router"; - -function SettingsButton() { - const preload = usePreloadRoute(); - - return ( - <button onClick={() => preload("/users/settings", { preloadData: true })}> - Load settings - </button> - ); -} -``` - -## Related - -- [`<A>`](/solid-router/reference/components/a) -- [`preload`](/solid-router/reference/preload-functions/preload) diff --git a/src/routes/solid-router/reference/primitives/use-resolved-path.mdx b/src/routes/solid-router/reference/primitives/use-resolved-path.mdx deleted file mode 100644 index 463ce1816..000000000 --- a/src/routes/solid-router/reference/primitives/use-resolved-path.mdx +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: useResolvedPath -use_cases: >- - resolved paths, relative paths, route paths -tags: - - path - - routing - - resolved -version: "1.0" -description: >- - useResolvedPath returns an accessor for a path resolved against the current route. ---- - -`useResolvedPath` returns an accessor for resolving a path against the current route. - -## Import - -```ts -import { useResolvedPath } from "@solidjs/router"; -``` - -## Type - -```ts -function useResolvedPath(path: () => string): () => string | undefined; -``` - -## Parameters - -### `path` - -- **Type:** `() => string` -- **Required:** Yes - -Accessor that returns the path to resolve. - -## Return value - -- **Type:** `() => string | undefined` - -Returns an accessor containing the resolved path, or `undefined` when the path cannot be resolved. - -## Behavior - -- Resolves the current `path()` value through the active route context. -- Returns `undefined` when the path cannot be resolved. - -## Examples - -### Basic usage - -```tsx -import { A, useResolvedPath } from "@solidjs/router"; - -function SettingsLink() { - const settingsPath = useResolvedPath(() => "settings"); - - return <A href={settingsPath() || ""}>Settings</A>; -} -``` - -## Related - -- [`A`](/solid-router/reference/components/a) -- [`Router`](/solid-router/reference/components/router) diff --git a/src/routes/solid-router/reference/primitives/use-search-params.mdx b/src/routes/solid-router/reference/primitives/use-search-params.mdx deleted file mode 100644 index 5ab7a819a..000000000 --- a/src/routes/solid-router/reference/primitives/use-search-params.mdx +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: useSearchParams -use_cases: >- - query parameters, search params, pagination, filters -tags: - - search - - query - - params - - url -version: "1.0" -description: >- - useSearchParams returns current query parameters and a query update function. ---- - -`useSearchParams` returns current query parameters and a setter for the URL search string. - -## Import - -```ts -import { useSearchParams } from "@solidjs/router"; -``` - -## Type - -```ts -type SearchParams = Record<string, string | string[] | undefined>; - -type SetSearchParams = Record< - string, - string | string[] | number | number[] | boolean | boolean[] | null | undefined ->; - -function useSearchParams<T extends SearchParams>(): [ - Partial<T>, - (params: SetSearchParams, options?: Partial<NavigateOptions>) => void, -]; -``` - -## Parameters - -`useSearchParams` takes no arguments. - -## Return value - -`useSearchParams` returns a tuple with the following: - -### `params` - -- **Type:** `Partial<T>` - -Reactive object containing the current query parameters. - -### `setParams` - -- **Type:** `(params: SetSearchParams, options?: Partial<NavigateOptions>) => void` - -Function that merges values into the current search string, then navigates to the result. - -## Behavior - -- New values are merged with [`useLocation`](/solid-router/reference/primitives/use-location)'s `search`. -- Keys are deleted when the new value is `null`, `undefined`, an empty string, or an empty array. -- Array values append each item. Other values set the key to `String(value)`. -- The current hash is preserved after the merged search string. -- Navigation uses `scroll: false` and `resolve: false` unless those options are overridden. - -## Examples - -### Basic usage - -```tsx -import { useSearchParams } from "@solidjs/router"; - -function Paginator() { - const [params, setParams] = useSearchParams(); - - const page = () => Number(params.page || "1"); - - return ( - <div> - <span>Current Page: {page()}</span> - <button onClick={() => setParams({ page: page() + 1 })}>Next</button> - </div> - ); -} -``` - -## Related - -- [`useParams`](/solid-router/reference/primitives/use-params) -- [`useLocation`](/solid-router/reference/primitives/use-location) -- [`useNavigate`](/solid-router/reference/primitives/use-navigate) diff --git a/src/routes/solid-router/reference/response-helpers/json.mdx b/src/routes/solid-router/reference/response-helpers/json.mdx deleted file mode 100644 index f4ad8de1a..000000000 --- a/src/routes/solid-router/reference/response-helpers/json.mdx +++ /dev/null @@ -1,147 +0,0 @@ ---- -title: json -use_cases: >- - json responses, action responses, query responses, revalidation headers -tags: - - json - - response - - revalidation -version: "1.0" -description: >- - json returns a custom JSON response. ---- - -`json` is a response helper that returns a returns a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) with a JSON body and a `customBody` reader for the original data. -It is intended for sending JSON data from a [query](/solid-router/reference/data-apis/query) or [action](/solid-router/concepts/actions) while also allowing configuration of query revalidation. - -## Import - -```ts -import { json } from "@solidjs/router"; -``` - -## Type - -```ts -function json<T>( - data: T, - init: { - revalidate?: string | string[]; - headers?: HeadersInit; - status?: number; - statusText?: string; - } = {} -): CustomResponse<T>; -``` - -## Parameters - -### `data` - -- **Type:** `T` -- **Required:** Yes - -The data to be serialized as JSON in the response body. -It must be a value that can be serialized with [`JSON.stringify`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). - -### `init` - -- **Type:** `RouterResponseInit` -- **Default:** `{}` -- **Required:** No - -A configuration object with the following properties: - -### `revalidate` - -- **Type:** `string | string[]` -- **Required:** No - -A query key or an array of query keys to revalidate. -Passing an empty array (`[]`) disables query revalidation entirely. - -#### `headers` - -- **Type:** `HeadersInit` -- **Required:** No - -An object containing any headers to be sent with the response. - -#### `status` - -- **Type:** `number` -- **Required:** No - -The HTTP status code of the response. -Defaults to [`200 OK`](http://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200). - -#### `statusText` - -- **Type:** `string` -- **Required:** No - -The status text associated with the status code. - -## Return value - -- **Type:** `CustomResponse<T>` - -Returns a `Response` object with a `customBody` function that returns `data`. - -## Behavior - -- Sets the `Content-Type` header to `"application/json"`. -- Serializes `data` with `JSON.stringify`. -- When `init.revalidate` is defined, `json` writes it to the `X-Revalidate` header with `toString()`. -- Values from `init.headers` are preserved unless overwritten by `json`. - -## Examples - -### Invalidating Data After a Mutation - -```tsx -import { For } from "solid-js"; -import { query, action, json, createAsync } from "@solidjs/router"; - -const getCurrentUserQuery = query(async () => { - return await fetch("/api/me").then((response) => response.json()); -}, "currentUser"); - -const getPostsQuery = query(async () => { - return await fetch("/api/posts").then((response) => response.json()); -}, "posts"); - -const createPostAction = action(async (formData: FormData) => { - const title = formData.get("title")?.toString(); - const newPost = await fetch("/api/posts", { - method: "POST", - body: JSON.stringify({ title }), - }).then((response) => response.json()); - - // Only revalidate the "posts" query. - return json(newPost, { revalidate: "posts" }); -}, "createPost"); - -function Posts() { - const currentUser = createAsync(() => getCurrentUserQuery()); - const posts = createAsync(() => getPostsQuery()); - - return ( - <div> - <p>Welcome back {currentUser()?.name}</p> - <ul> - <For each={posts()}>{(post) => <li>{post.title}</li>}</For> - </ul> - <form action={createPostAction} method="post"> - <input name="title" /> - <button>Create Post</button> - </form> - </div> - ); -} -``` - -## Related - -- [`query`](/solid-router/reference/data-apis/query) -- [`action`](/solid-router/reference/data-apis/action) diff --git a/src/routes/solid-router/reference/response-helpers/redirect.mdx b/src/routes/solid-router/reference/response-helpers/redirect.mdx deleted file mode 100644 index 0aa48d44d..000000000 --- a/src/routes/solid-router/reference/response-helpers/redirect.mdx +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: redirect -use_cases: >- - redirects, response redirects, navigation responses, revalidation headers -tags: - - redirect - - response - - navigation - - revalidation -version: "1.0" -description: >- - redirect returns a custom redirect response. ---- - -`redirect` is a response helper that returns a [`Response` object](https://developer.mozilla.org/en-US/docs/Web/API/Response) object that instructs the router to navigate to a different route when returned or thrown from a [query](/solid-router/reference/data-apis/query) or [action](/solid-router/concepts/actions). - -## Import - -```ts -import { redirect } from "@solidjs/router"; -``` - -## Type - -```ts -type RouterResponseInit = Omit<ResponseInit, "body"> & { - revalidate?: string | string[]; -}; - -function redirect( - url: string, - init?: - | number - | { - revalidate?: string | string[]; - headers?: HeadersInit; - status?: number; - statusText?: string; - } -): CustomResponse<never>; -``` - -## Parameters - -### `url` - -- **Type:** `string` -- **Required:** Yes - -The absolute or relative URL to which the redirect should occur. - -### `init` - -- **Type:** `number | RouterResponseInit` -- **Default:** `302` -- **Required:** No - -Redirect status code or response options. - -### `revalidate` - -- **Type:** `string | string[]` -- **Required:** No - -Key or keys written to the `X-Revalidate` response header. - -#### `status` - -- **Type:** `number` -- **Required:** No - -The HTTP status code for the redirect. -Defaults to [`302 Found`)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302). - -## Return value - -- **Type:** `CustomResponse<never>` - -Returns a `Response` object with a `Location` header. - -## Behavior - -- A numeric `init` is used as the response status. -- Object `init` values default `status` to `302` when `status` is undefined. -- Writes `url` to the `Location` header. -- Defined `revalidate` values are written to the `X-Revalidate` header with `toString()`. - -## Examples - -### Basic usage - -```ts -import { query, redirect } from "@solidjs/router"; - -const getCurrentUser = query(async () => { - const response = await fetch("/api/me"); - - if (response.status === 401) { - return redirect("/login"); - } - - return response.json(); -}, "currentUser"); -``` - -## Related - -- [`json`](/solid-router/reference/response-helpers/json) -- [`reload`](/solid-router/reference/response-helpers/reload) diff --git a/src/routes/solid-router/reference/response-helpers/reload.mdx b/src/routes/solid-router/reference/response-helpers/reload.mdx deleted file mode 100644 index 94c390963..000000000 --- a/src/routes/solid-router/reference/response-helpers/reload.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: reload -use_cases: >- - data refresh, cache invalidation, after mutations, updating queries, form - submissions, data synchronization -tags: - - reload - - cache - - revalidation - - mutations - - queries - - refresh -version: "1.0" -description: >- - Reload and revalidate specific queries after mutations. Efficiently update - cached data without full page refreshes for better UX. ---- - -The `reload` function returns a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) object that instructs the router to revalidate specific queries when returned or thrown from a [query](/solid-router/reference/data-apis/query) or [action](/solid-router/concepts/actions). - -## Import - -```ts -import { reload } from "@solidjs/router"; -``` - -## Type - -```ts -function reload(init?: { - revalidate?: string | string[]; - headers?: HeadersInit; - status?: number; - statusText?: string; -}): CustomResponse<never>; -``` - -## Parameters - -### `init` - -- **Type:** `{ revalidate?: string | string[]; headers?: HeadersInit; status?: number; statusText?: string; }` -- **Required:** No - -An optional configuration object with the following properties: - -#### `revalidate` - -- **Type:** `string | string[]` -- **Required:** No - -A query key or an array of query keys to revalidate. - -#### `headers` - -- **Type:** `HeadersInit` -- **Required:** No - -An object containing any headers to be sent with the response. - -#### `status` - -- **Type:** `number` -- **Required:** No - -The HTTP status code of the response. -Defaults to [`200 OK`](http://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200). - -#### `statusText` - -- **Type:** `string` -- **Required:** No - -The status text associated with the status code. - -## Examples - -### Basic Usage - -```ts -import { action, reload } from "@solidjs/router"; - -const savePreferencesAction = action(async () => { - // ... Saves the user preferences. - - // Only revalidate the "userPreferences" query. - return reload({ revalidate: ["userPreferences"] }); -}, "savePreferences"); -``` diff --git a/src/routes/solid-start/v1/(0)building-your-application/(0)routing.mdx b/src/routes/solid-start/v1/(0)building-your-application/(0)routing.mdx deleted file mode 100644 index 1f80d3526..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(0)routing.mdx +++ /dev/null @@ -1,301 +0,0 @@ ---- -title: Routing -use_cases: >- - page navigation, url structure, nested layouts, dynamic paths, route - organization, site architecture -tags: - - routing - - navigation - - pages - - layouts - - dynamic - - filesystem -version: "1.0" -description: >- - Build your SolidStart app with file-based routing. Create pages, nested - layouts, and dynamic routes with simple file structure. ---- - -Routing serves as a key component of web applications. -Within SolidStart, there are two types: - -- **UI routes** — define the user interface in your app -- **[API routes](/solid-start/v1/building-your-application/api-routes)** — define the serverless functions in your app - -To read more about API routes, [see the API Routes section.](/solid-start/v1/building-your-application/api-routes) - -## Creating new routes - -SolidStart uses file based routing which is a way of defining your routes by creating files and folders in your project. -This includes your pages and API routes. - -SolidStart traverses your `routes` directory, collects all of the routes, and then makes them accessible using the [`<FileRoutes />`](/solid-start/v1/reference/routing/file-routes). -This component will only include your UI routes, not your API routes. -Rather than manually defining each `Route` inside a `Router` component, `<FileRoutes />` will generate the routes for you based on the file system. - -Because `<FileRoutes />` returns a routing config object, you can use it with the router of your choice. -In this example, we use [`solid-router`](/solid-router): - -```tsx {7-9} title="app.tsx" -import { Suspense } from "solid-js"; -import { Router } from "@solidjs/router"; -import { FileRoutes } from "@solidjs/start/router"; - -export default function App() { - return ( - <Router root={(props) => <Suspense>{props.children}</Suspense>}> - <FileRoutes /> - </Router> - ); -} -``` - -The `<Router />` component expects a `root` prop which functions as the root layout of your entire app. -You will want to make sure `props.children` is wrapped in `<Suspense />` since each component will be lazy-loaded automatically. -Without this, you could see some unexpected hydration errors. - -`<FileRoutes />` will generate a route for each file in the `routes` directory and its subdirectories. For a route to be rendered as a page, it must default export a component. -This component represents the content that will be rendered when users visit the page: - -```tsx title="routes/index.tsx" -export default function Index() { - return <div>Welcome to my site!</div>; -} -``` - -This means that all you have to do is create a file in your `routes` folder and SolidStart takes care of everything else needed to make that route available to visit in your application! - -## File based routing - -Each file in the `routes` directory is treated as a route. -To create a new route or page in your application, simply create a new file in the `routes` directory. -The file name will be the URL path for the route: - -- `example.com/blog` ➜ `/routes/blog.tsx` -- `example.com/contact` ➜ `/routes/contact.tsx` -- `example.com/directions` ➜ `/routes/directions.tsx` - -### Nested routes - -If you need nested routes, you can create a directory with the name of the preceding route segment, and create new files in that directory: - -- `example.com/blog/article-1` ➜ `/routes/blog/article-1.tsx` -- `example.com/work/job-1` ➜ `/routes/work/job-1.tsx` - -When a file is named `index`, it will be rendered when there are no additional URL route segments being requested for a matching directory: - -- `example.com` ➜ `/routes/index.tsx` -- `example.com/socials` ➜ `/routes/socials/index.tsx` - -### Nested layouts - -If you want to create nested layouts you can create a file with the same name as a route folder. - -```jsx {2} -|-- routes/ - |-- blog.tsx // layout file - |-- blog/ - |-- article-1.tsx // example.com/blog/article-1 - |-- article-2.tsx // example.com/blog/article-2 -``` - -In this case, the `blog.tsx` file will act as a layout for the articles in the `blog` folder. -You can reference the child's content -by using `props.children` in the layout. - -```tsx tab title="TypeScript" -// routes/blog.tsx -import { RouteSectionProps } from "@solidjs/router"; - -export default function BlogLayout(props: RouteSectionProps) { - return <div>{props.children}</div>; -} -``` - -```jsx tab title="JavaScript" -// routes/blog.jsx -export default function BlogLayout(props) { - return <div>{props.children}</div>; -} -``` - -**Note**: Creating a `blog/index.tsx` or `blog/(blogIndex).tsx` is not the same as it would only be used for the index route. - -## Renaming Index - -By default, the component that is rendered for a route comes from the default export of the `index.tsx` file in each folder. -However, this can make it difficult to find the correct `index.tsx` file when searching, since there will be multiple files with that name. - -To avoid this, you can rename the `index.tsx` file to the name of the folder it is in, enclosed in parentheses. - -This way, it will be treated as the default export for that route: - -```jsx {9} -|-- routes/ // example.com - |-- blog/ - |-- article-1.tsx // example.com/blog/article-1 - |-- article-2.tsx - |-- work/ - |-- job-1.tsx // example.com/work/job-1 - |-- job-2.tsx - |-- socials/ - |-- (socials).tsx // example.com/socials -``` - -#### Escaping nested routes - -When you have a path that is nested but wish for it to have a separate Layout, you can escape the nested route by applying a name between `( )`. -This will allow you to create a new route that is not nested under the previous route: - -```jsx {5-6} -|-- routes/ // example.com - |-- users/ - |-- index.tsx // example.com/users - |-- projects.tsx // example.com/users/projects - |-- users(details)/ - |-- [id].tsx // example.com/users/1 -``` - -Additionally, you can incorporate nested layouts of their own: - -```tsx {2, 78} -|-- routes/ - |-- users.tsx - |-- users(details).tsx - |-- users/ - |-- index.tsx - |-- projects.tsx - |-- users(details)/ - |-- [id].tsx -``` - -### Dynamic routes - -Dynamic routes are routes that can match any value for one segment of the route. -When your URL path contains a dynamic segment, square brackets (`[]`) are used to define the dynamic segment: - -- `example.com/users/:id` ➜ `/routes/users/[id].tsx` -- `example.com/users/:id/:name` ➜ `/routes/users/[id]/[name].tsx` -- `example.com/*missing` ➜ `/routes/[...missing].tsx` - -This allows you to create a single route that can match any value for that segment of the URL path. -For example, `/users/1` and `/users/2` are both valid routes and rather than defining separate routes for each user, you can use a dynamic route to match any value for the `id` segment. - -```tsx {3} -|-- routes/ - |-- users/ - |-- [id].tsx -``` - -For example, using `solid-router`, you could use the [`useParams`](/solid-router/reference/primitives/use-params) primitive to match the dynamic segment: - -```tsx title="routes/users/[id].tsx" -import { useParams } from "@solidjs/router"; - -export default function UserPage() { - const params = useParams(); - return <div>User {params.id}</div>; -} -``` - -#### Optional parameter - -If you have optional parameters in your route, you can use the double square brackets (`[[id]]`) to define the dynamic segment. -This will match a route with or without a parameter. - -```tsx {3} -|-- routes/ - |-- users/ - |-- [[id]].tsx -``` - -In this case, some pages that could be matched include: - -- `/users` -- `/users/1` -- `/users/abc` - -#### Catch-all routes - -Catch-all routes are a special type of dynamic route that can match any number of segments. -They are defined using square brackets with `...` before the label for the route (e.g. `[...post]`). - -```tsx {4} -|-- routes/ - |-- blog/ - |-- index.tsx - |-- [...post].tsx -``` - -A catch-all route will have one parameter which is a forward-slash delimited string of all the URL segments after the last valid segment. -For example, with the route `[...post]` and a URL path of `/post/foo` the `params` object returned from the `useParams` primitive will have a `post` property with the value of `post/foo`. -For a URL path of `/post/foo/baz` it will be `post/foo/baz`. - -```tsx title="routes/blog/[...post].tsx" -import { useParams } from "@solidjs/router"; - -export default function BlogPage() { - const params = useParams(); - return <div>Blog {params.post}</div>; -} -``` - -## Route groups - -Using route groups, you can organize your routes in a way that makes sense for your application, without affecting the URL structure. -Since file-based routing is based on the file system, it can be difficult to organize your routes in a way that makes sense for your application. - -In SolidStart, route groups are defined by using parenthesis (`()`) surrounding the folder name: - -```tsx {2} -|-- routes/ - |-- (static) - |-- about-us // example.com/about-us - |-- index.tsx - |-- contact-us // example.com/contact-us - |-- index.tsx -``` - -## Additional route config - -SolidStart offers a way to add additional route configuration outside of the file system. -Since SolidStart supports the use of other routers, you can use the `route` export provided by `<FileRoutes />` to define the route configuration for the router of your choice. - -```jsx tab title="TypeScript" {3-7} -import type { RouteSectionProps, RouteDefinition } from "@solidjs/router"; - -export const route = { - preload() { - // define preload function - } -} satisfies RouteDefinition - -export default function UsersLayout(props: RouteSectionProps) { - return ( - <div> - <h1>Users</h1> - {props.children} - </div> - ); -} -``` - -```jsx tab title="JavaScript" {3-7} -export const route = { - preload() { - // define preload function - }, -}; - -export default function UsersLayout(props) { - return ( - <div> - <h1>Users</h1> - {props.children} - </div> - ); -} -``` - -[api-routes]: /core-concepts/api-routes -[fileroutes]: /api/FileRoutes diff --git a/src/routes/solid-start/v1/(0)building-your-application/(1)api-routes.mdx b/src/routes/solid-start/v1/(0)building-your-application/(1)api-routes.mdx deleted file mode 100644 index 184d34b7a..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(1)api-routes.mdx +++ /dev/null @@ -1,241 +0,0 @@ ---- -title: API routes -use_cases: >- - rest api, graphql endpoints, trpc setup, webhooks, oauth callbacks, pdf - generation, third-party integrations -tags: - - api - - rest - - graphql - - trpc - - endpoints - - server - - http -version: "1.0" -description: >- - Create API routes in SolidStart for REST, GraphQL, or tRPC endpoints. Handle - HTTP methods, sessions, and external integrations. ---- - -While Server Functions can be a good way to write server-side code for data needed by your UI, sometimes you need to expose API routes. -Some reasons for wanting API Routes include: - -- There are additional clients that want to share this logic. -- Exposing a GraphQL or tRPC endpoint. -- Exposing a public-facing REST API. -- Writing webhooks or auth callback handlers for OAuth. -- Having URLs not serving HTML, but other kinds of documents like PDFs or images. - -For these use cases, SolidStart provides a way to write these routes in a way that is easy to understand and maintain. -API routes are just similar to other routes and follow the same filename conventions as [UI Routes](/solid-start/v1/building-your-application/routing). - -The difference between API routes and UI routes is in what you should export from the file. -UI routes export a default Solid component, while API Routes do not. -Rather, they export functions that are named after the HTTP method that they handle. - -:::note -API routes are prioritized over UI route alternatives. -If you want to have them overlap at the same path remember to use `Accept` headers. -Returning without a response in a `GET` route will fallback to UI route handling. -::: - -## Writing an API route - -To write an API route, you can create a file in a directory. -While you can name this directory anything, it is common to name it `api` to indicate that the routes in this directory are for handling API requests: - -```tsx title="routes/api/test.ts" -export function GET() { - // ... -} - -export function POST() { - // ... -} - -export function PATCH() { - // ... -} - -export function DELETE() { - // ... -} -``` - -API routes get passed an `APIEvent` object as their first argument. -This object contains: - -- `request`: [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) object representing the request sent by the client. -- `params`: Object that contains the dynamic route parameters. For example, if the route is `/api/users/:id`, and the request is made to `/api/users/123`, then `params` will be `{ id: 123 }`. -- `fetch`: An internal `fetch` function that can be used to make requests to other API routes without worrying about the `origin` of the URL. - -An API route is expected to return JSON or a `Response` object. -In order to handle all methods, you can define a handler function that binds multiple methods to it: - -```tsx title="routes/api/all.ts" -async function handler() { - // ... -} - -export const GET = handler; -export const POST = handler; -// ... -``` - -An example of an API route that returns products from a certain category and brand is shown below: - -```tsx title="routes/api/product/[category]/[brand].ts" -import type { APIEvent } from "@solidjs/start/server"; -import store from "./store"; - -export async function GET({ params }: APIEvent) { - console.log(`Category: ${params.category}, Brand: ${params.brand}`); - const products = await store.getProducts(params.category, params.brand); - return products; -} -``` - -## Session management - -Since HTTP is a stateless protocol, you need to manage the state of the session on the server. -For example, if you want to know who the user is, the most secure way of doing this is through the use of HTTP-only cookies. -Cookies are a way to store data in the user's browser that persist in the browser between requests. - -The user's request is exposed through the `Request` object. -Through parsing the [`Cookie`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie) header, the cookies can be accessed and any helpers from `vinxi/http` can be used to make that a bit easier. - -```tsx -import type { APIEvent } from "@solidjs/start/server"; -import { getCookie } from "vinxi/http"; -import store from "./store"; - -export async function GET(event: APIEvent) { - const userId = getCookie("userId"); - if (!userId) { - return new Response("Not logged in", { status: 401 }); - } - const user = await store.getUser(event.params.userId); - if (user.id !== userId) { - return new Response("Not authorized", { status: 403 }); - } - return user; -} -``` - -In this example, you can see that the `userId` is read from the cookie and then used to look up the user in the store. -For more information on how to use cookies for secure session management, read the [session documentation](/solid-start/v1/advanced/session). - -## Exposing a GraphQL API - -SolidStart makes it easy to [implement a GraphQL API](https://graphql.org/). -GraphQL is a query language for APIs and a runtime for executing those queries by using a type system you define for your data. - -To implement a GraphQL API, you need to define a schema and resolvers. -The `graphql` function takes a GraphQL schema and returns a function that can be used as an API route handler. - -First, to implement a GraphQL API, install the `graphql` library. -Following that, you can implement your schema and resolvers in a file and then export a handler function that will be used as the API route: - -```tsx title="routes/graphql.ts" -import { buildSchema, graphql } from "graphql"; -import type { APIEvent } from "@solidjs/start/server"; - -// Define GraphQL Schema -const schema = buildSchema(` - type Message { - message: String - } - - type Query { - hello(input: String): Message - goodbye: String - } -`); - -// Define GraphQL Resolvers -const rootValue = { - hello: () => { - return { - message: "Hello World", - }; - }, - goodbye: () => { - return "Goodbye"; - }, -}; - -// request handler -const handler = async (event: APIEvent) => { - // get request body - const body = await new Response(event.request.body).json(); - - // pass query and save results - const result = await graphql({ rootValue, schema, source: body.query }); - - // send query result - return result; -}; - -export const GET = handler; - -export const POST = handler; -``` - -## Exposing a tRPC server route - -[tRPC](https://trpc.io/) is a modern TypeScript-first API framework that is designed to be easy to use and understand. - -To expose a tRPC server route, you need to write your router. -Once you have written your router, you can put it in a separate file so that you can export the type for your client. - -```tsx title="lib/router.ts" -import { initTRPC } from "@trpc/server"; -import { wrap } from "@decs/typeschema"; -import { string } from "valibot"; - -const t = initTRPC.create(); - -export const appRouter = t.router({ - hello: t.procedure.input(wrap(string())).query(({ input }) => { - return `hello ${input ?? "world"}`; - }), -}); - -export type AppRouter = typeof appRouter; -``` - -An example of a simple client that you can use to fetch data from your tRPC server is shown below: - -```tsx title="lib/trpc.ts" -import { createTRPCProxyClient, httpBatchLink, loggerLink } from "@trpc/client"; -import type { AppRouter } from "./router"; - -export const client = createTRPCProxyClient<AppRouter>({ - links: [ - loggerLink(), - httpBatchLink({ url: "http://localhost:3000/api/trpc" }), - ], -}); -``` - -Finally, you can use the `fetch` adapter to write an API route that acts as the tRPC server. - -```tsx title="routes/api/trpc/[trpc].ts" -import { type APIEvent } from "@solidjs/start/server"; -import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; -import { appRouter } from "~/lib/router"; - -const handler = (event: APIEvent) => - fetchRequestHandler({ - endpoint: "/api/trpc", - req: event.request, - router: appRouter, - createContext: () => ({}), - }); - -export const GET = handler; - -export const POST = handler; -``` - -To learn more about tRPC, you can read the [tRPC documentation](https://trpc.io/docs). diff --git a/src/routes/solid-start/v1/(0)building-your-application/(2)css-and-styling.mdx b/src/routes/solid-start/v1/(0)building-your-application/(2)css-and-styling.mdx deleted file mode 100644 index aa2d79460..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(2)css-and-styling.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: CSS and styling -use_cases: >- - styling components, css modules, scoped styles, component styling, design - system setup, visual customization -tags: - - css - - styling - - modules - - components - - design - - vite -version: "1.0" -description: >- - Style your SolidStart components with CSS, CSS modules, and other styling - solutions. Implement scoped styles and design systems. ---- - -SolidStart is a standards-based framework that, instead of modifying the behavior of the [`<style>` tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style), strives to build on top of it. - -## Styling components - -Vite provides a simple way to [manage CSS for complex web applications](https://vitejs.dev/guide/features.html#css). -It does this by allowing users to import CSS using ESM syntax anywhere within the component tree. -For example, you can write CSS in a file accompanying your component file: - -``` -src/ -├── components/ -│ ├── Card.tsx -│ ├── Card.css -``` - -To use the CSS in the component, you can define the CSS in the `Card.css` file and import it in the `Card.tsx` file: - -```css title="Card.css" -.card { - background-color: #446b9e; -} - -h1 { - font-size: 1.5em; - font-weight: bold; -} - -p { - font-size: 1em; - font-weight: normal; -} -``` - -```tsx title="Card.tsx" -import "./Card.css"; - -const Card = (props) => { - return ( - <div class="card"> - <h1>{props.title}</h1> - <p>{props.text}</p> - </div> - ); -}; -``` - -### CSS modules for scoped styles - -SolidStart also supports [vite's CSS modules](https://vitejs.dev/guide/features.html#css-modules). -Through [CSS modules](https://github.com/css-modules/css-modules), you can scope certain CSS to a component and use the CSS class in multiple components to style them differently. - -For this feature to work, the `.css` file must be named with the `.module.css` extension. -This convention also works for `.scss` and `.sass` files, which can be named with the `.module.scss` and `.module.sass` extensions, respectively. - -```css title="Card.module.css" -.card { - background-color: #446b9e; -} - -div.card > h1 { - font-size: 1.5em; - font-weight: bold; -} - -div.card > p { - font-size: 1em; - font-weight: normal; -} -``` - -When first using CSS modules, you will encounter an error when trying to use the class attribute in your components. -This is because, behind the scenes, classes defined in CSS modules are renamed to a series of random letters. -When classes are hard coded using the class attribute (`class="card"`), Solid is not aware that it should rename `card` to something different. - -To fix this, you can import classes used in your CSS module. -The import object can be thought of as `humanClass: generatedClass` and within the component, the key (ie. the class on the element) is used to get the unique, generated class name. - -```jsx -import styles from "./Card.module.css"; - -const Card = (props) => { - return ( - <div class={styles.card}> - <h1>{props.title}</h1> - <p>{props.text}</p> - </div> - ); -}; -``` - -## Other ways to style components - -SolidStart is built on top of Solid, meaning styling is not limited to CSS. -To see other ways to style components, see the [styling section in the Solid documentation](/guides/styling-your-components). diff --git a/src/routes/solid-start/v1/(0)building-your-application/(3)data-fetching.mdx b/src/routes/solid-start/v1/(0)building-your-application/(3)data-fetching.mdx deleted file mode 100644 index 0f0e55589..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(3)data-fetching.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: "Data fetching" -version: "1.0" ---- - -Fetching data from a remote API or database is a core task for most applications. -[Solid](/) and [Solid Router](/solid-router) provide foundational tools like the [`createResource` primitive](/guides/fetching-data) and [queries](/solid-router/data-fetching/queries) to manage asynchronous data. - -SolidStart builds on these capabilities, extending them to provide a comprehensive solution for data fetching in a full-stack environment. - -This page assumes you are familiar with the fundamental concepts of Solid and Solid Router. -If you are a beginner, we highly recommend starting with the [queries documentation](/solid-router/data-fetching/queries). -You can also find many practical examples in the [data fetching how-to guide](/solid-start/v1/guides/data-fetching). - -## Server functions and queries - -Server functions provide a way to write functions that run exclusively on the server. -This makes it safe to fetch data directly from a database without relying on a separate API endpoint. - -Server functions integrate seamlessly with queries, as they can be used as the fetcher for a query. - -```tsx -import { query, redirect } from "@solidjs/router"; -import { useSession } from "vinxi/http"; -import { db } from "./db"; - -const getCurrentUserQuery = query(async (id: string) => { - "use server"; - const session = await useSession({ - password: process.env.SESSION_SECRET as string, - name: "session", - }); - - if (session.data.userId) { - return await db.users.get({ id: session.data.userId }); - } else { - throw redirect("/login"); - } -}, "currentUser"); -``` - -In this example, the `getCurrentUserQuery` retrieves the session data, and if an authenticated user exists, it gets their information from the database and returns it. -Otherwise, it redirects the user to the login page. -All of these operations are performed completely on the server regardless of how the query is called. - -:::caution[Modifying headers after streaming] -Once streaming begins, response headers (including status and cookies) are sent and cannot be changed. -Any header-modifying logic within a server function, such as redirects or APIs like `useSession` that set cookies, must run before streaming starts; -otherwise, this error will occur: -`Cannot set headers after they are sent to the client.` - -To avoid this, disable streaming for queries that may modify headers by enabling the [`deferStream`](/solid-router/reference/data-apis/create-async#deferstream) option. - -```tsx -const user = createAsync(() => getCurrentUserQuery(), { deferStream: true }); -``` - -::: diff --git a/src/routes/solid-start/v1/(0)building-your-application/(4)data-mutation.mdx b/src/routes/solid-start/v1/(0)building-your-application/(4)data-mutation.mdx deleted file mode 100644 index d5174bc5f..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(4)data-mutation.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "Data mutation" -version: "1.0" ---- - -Mutating data on a server is a common task in most applications. -[Solid Router](/solid-router) provides [actions](/solid-router/concepts/actions) to manage data mutations effectively. - -SolidStart builds upon the capabilities of actions, extending their scope to provide a comprehensive, full-stack solution for data mutations. - -This page does not cover the foundational concepts from Solid Router. -If you are a beginner, we highly recommend starting with the [actions documentation](/solid-router/concepts/actions). -You can also find many practical examples in the [data mutation how-to guide](/solid-start/v1/guides/data-mutation). - -## Server functions and actions - -Server functions allow an action to run exclusively on the server. -This enables performing sensitive operations—such as writing to a database or working with sessions—directly within the action. - -```tsx -import { action, redirect } from "@solidjs/router"; -import { useSession } from "vinxi/http"; -import { db } from "./db"; - -const logoutAction = action(async () => { - "use server"; - const session = await useSession({ - password: process.env.SESSION_SECRET as string, - name: "session", - }); - - if (session.data.sessionId) { - await session.clear(); - await db.session.delete({ id: sessionId }); - } - - throw redirect("/"); -}, "logout"); -``` - -In this example, the entire `logoutAction` runs on the server. -It safely accesses the session to retrieve the `sessionId` and performs a database deletion without exposing this logic to the client. -The `redirect` then navigates the user back to the home page. - -## Single-flight mutations - -When a piece of data changes on the server, the new data needs to be fetched so the UI doesn't fall out of sync. -Traditionally, this is done in two separate HTTP requests: one to update the data, and a second to fetch the new data. - -Single-flight mutations are a unique feature of SolidStart that handles this pattern in a single request. -This is enabled when two requirements are met: - -1. The action that updates the data must execute on the server using server functions. -2. The data that the action updated must be preloaded. - If the action performs a redirect, preloading needs to happen on the destination page. - -```tsx title="src/routes/products/[id].tsx" -import { - action, - query, - createAsync, - type RouteDefinition, - type RouteSectionProps, -} from "@solidjs/router"; -import { db } from "./db"; - -const updateProductAction = action(async (id: string, formData: FormData) => { - "use server"; - const name = formData.get("name")?.toString(); - await db.products.update(id, { name }); -}, "updateProduct"); - -const getProductQuery = query(async (id: string) => { - "use server"; - return await db.products.get(id); -}, "product"); - -export const route = { - preload: ({ params }) => getProductQuery(params.id as string), -} satisfies RouteDefinition; - -export default function ProductDetail(props: RouteSectionProps) { - const product = createAsync(() => getProductQuery(props.params.id as string)); - - return ( - <div> - <p>Current name: {props.data.product?.name}</p> - <form - action={updateProductAction.with(props.params.id as string)} - method="post" - > - <input name="name" placeholder="New name" /> - <button>Save</button> - </form> - </div> - ); -} -``` - -In this example, `updateProductAction` updates the product within a server function, and `getProductQuery` is responsible for fetching the product data. -Note that `getProductQuery` is preloaded on the route. - -When a user submits the form, a single POST request is sent to the server. -After the action completes, `getProductQuery` is automatically revalidated. -Because it's preloaded, SolidStart can trigger the revalidation on the server and stream the result back to the client in the same response. diff --git a/src/routes/solid-start/v1/(0)building-your-application/(5)head-and-metadata.mdx b/src/routes/solid-start/v1/(0)building-your-application/(5)head-and-metadata.mdx deleted file mode 100644 index 24fdb5734..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(5)head-and-metadata.mdx +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: Head and metadata -use_cases: >- - seo optimization, page titles, meta tags, og tags, social sharing, search - engine visibility, dynamic metadata -tags: - - seo - - metadata - - head - - title - - meta - - og-tags -version: "1.0" -description: >- - Manage SEO and metadata in SolidStart with dynamic titles, meta tags, and Open - Graph tags for better search visibility. ---- - -SolidStart does not come with a metadata library. -In cases where you want to customize the content in the `head` of your `document`, you can use the `@solidjs/meta` library. - -<div id="npm">```bash frame="none" npm i @solidjs/meta ```</div> - -The common elements used in the [`head`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) are: - -- [`title`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title): Specifies the title of the page, used by the browser tab and headings of search results. -- [`meta`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta): Specifies a variety of metadata about the page specified by `name`, ranging from favicon, character set to OG tags for SEO. -- [`link`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link): Adds assets like stylesheets or scripts for the browser to load for the page. -- [`style`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style): Adds inline styles to the page. - -## Inside a Route component - -When applying metadata to a specific route, you can use the `Title`: - -```tsx {6} -import { Title } from "@solidjs/meta"; - -export default function About() { - return ( - <> - <Title>About -

    About

    - - ); -} -``` - -These tags will be applied for that specific route only and will be removed from `document.head` once a user navigates away from the page. -`routeData` can also be used here to create titles and SEO metadata that is specific to the dynamic parts of the route. - -## Adding a site suffix in Title - -Custom components can be created to wrap the `Title` component to add a site-specific prefix to all the titles: - -```tsx {2} -export default function MySiteTitle(props) { - return {props.children} | My Site; -} -``` - -```tsx { 6 } -import MySiteTitle from "~/components/MySiteTitle"; - -export default function About() { - return ( - <> - About -

    About

    - - ); -} -``` - -## Using async data in `Title` - -Resources can be used to create titles specific to the dynamic parts of the route: - -```tsx { 10 } -import { Title } from "@solidjs/meta"; -import { RouteSectionProps } from "@solidjs/router"; -import { createResource, Show } from "solid-js"; - -export default function User(props: RouteSectionProps) { - const [user] = createResource(() => fetchUser(props.params.id)); - - return ( - - {user()?.name} -

    {user()?.name}

    -
    - ); -} -``` - -For this example, `routeData` can be used to retrieve the user's name from the `id` in `/users/:id` and use it in the `Title` component. -Similarly, other information can be used to build up other tags for SEO. - -## Adding SEO tags - -SEO tags like `og:title`, `og:description`, `og:image`, use the `Meta` component. -Since these tags may want to be used across multiple routes, they can be added inside the `Head` of the `root.tsx` file. - -```tsx { 5-15 } -export default function Root() { - return ( - - - - - - - - - - ); -} -``` - -If you need to add route-specific information inside your route, much like the `Title` component, you can use the `Meta` component within the desired route. -This overrides the `Meta` tags used within the `Head` component. - -```tsx -import MySiteTitle from "~/components/MySiteTitle"; - -export default function About() { - return ( - <> - About - - - -

    About

    - - ); -} -``` diff --git a/src/routes/solid-start/v1/(0)building-your-application/(6)route-prerendering.mdx b/src/routes/solid-start/v1/(0)building-your-application/(6)route-prerendering.mdx deleted file mode 100644 index e4290c360..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(6)route-prerendering.mdx +++ /dev/null @@ -1,53 +0,0 @@ ---- -title: Route Pre-rendering -use_cases: >- - static site generation, ssg, blog sites, documentation, marketing pages, - performance optimization, seo improvement -tags: - - prerender - - ssg - - static - - performance - - build - - seo -version: "1.0" -description: >- - Pre-render SolidStart routes to static HTML for faster loads and better SEO. - Perfect for blogs, docs, and marketing sites. ---- - -Route pre-rendering powers Static Site Generation (SSG) by producing static HTML pages during the build process. -This results in faster load times and better SEO, making it especially useful for content-rich sites such as documentation, blogs, and marketing pages. -Static files are served without server-side processing at runtime. - -Configure prerendering for specific routes using the `routes` option - -```js { 6 } -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - prerender: { - routes: ["/", "/about"], - }, - }, -}); -``` - -Or to pre-render all routes, you can pass `true` to the `crawlLinks` option - -```js { 6 } -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - prerender: { - crawlLinks: true, - }, - }, -}); -``` - -For advanced pre-rendering options, refer to [Nitro's documentation](https://nitro.build/config#prerender). - -[SolidBase](https://solidbase.dev) simplifies SSG development with built-in support for fast, pre-rendered Markdown and MDX pages. diff --git a/src/routes/solid-start/v1/(0)building-your-application/(7)static-assets.mdx b/src/routes/solid-start/v1/(0)building-your-application/(7)static-assets.mdx deleted file mode 100644 index 06e9b2117..000000000 --- a/src/routes/solid-start/v1/(0)building-your-application/(7)static-assets.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Static assets -use_cases: >- - images, fonts, documents, favicon, robots.txt, service workers, media files, - public resources -tags: - - assets - - images - - public - - static - - media - - files -version: "1.0" -description: >- - Manage static assets in SolidStart using the public directory or imports. - Serve images, fonts, documents, and media files. ---- - -Within SolidStart there are two ways to import static assets into your project: using the public directory and using imports. - -## Public directory - -Rich web applications use assets to create visuals. -In SolidStart, the `/public` directory can be used to store static assets. -These assets are served at the exact path they are in, relative to the public directory: - -``` -|-- public -| favicon.ico -> /favicon.ico -| |-- images -| | |-- logo.png -> /images/logo.png -| | |-- background.png -> /images/background.png -| |-- models -| | |-- player.gltf -> /models/player.gltf -| |-- documents -| | |-- report.pdf -> /documents/report.pdf -``` - -If you would like to reference an asset in the public directory, you can use the absolute path to the asset: - -```tsx { 5 } -export default function About() { - return ( - <> -

    About

    - Solid logo - - ); -} -``` - -This is ideal when you want to have human-readable, stable references to static assets. -This can be useful for assets such as: - -- documents -- service workers -- images, audio, and video -- manifest files -- metadata files (e.g., `robots.txt`, sitemaps) -- favicon - -## Importing assets - -Vite provides a way to import assets directly into your Solid components: - -```tsx -import logo from "./solid.png"; - -export default function About() { - return ( - <> -

    About

    - Solid logo - // Renders - Solid logo - - ); -} -``` - -When you use imports, Vite will create a hashed filename. -For example, `solid.png` will become `solid.2d8efhg.png`. - -## Public directory versus imports - -The public directory and imports are both valid ways to include static assets in your project. -The driver to use one over the other is based on your use case. - -For dynamic updates to your assets, using the public directory is the best choice. -It allows you to maintain full control over the asset URL paths, ensuring that the links remain consistent even when the assets are updated. - -When using imports, the filename is hashed and therefore will not be predictable over time. -This can be beneficial for cache busting but detrimental if you want to send someone a link to the asset. diff --git a/src/routes/solid-start/v1/(0)index.mdx b/src/routes/solid-start/v1/(0)index.mdx deleted file mode 100644 index e94da2def..000000000 --- a/src/routes/solid-start/v1/(0)index.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Overview -titleTemplate: ":title" -use_cases: >- - getting started, new projects, learning solidstart, framework overview, - architecture decisions -tags: - - overview - - introduction - - getting-started - - features - - ssr - - csr - - ssg -version: "1.0" -description: >- - SolidStart meta-framework overview: Build modern web apps with fine-grained - reactivity, isomorphic routing, and flexible rendering. ---- - -SolidStart is an open source meta-framework designed to unify components that make up a web application. -It is built on top of [Solid](/) and uses [Vinxi](https://vinxi.vercel.app/), an agnostic Framework Bundler that combines the power of [Vite](https://vitejs.dev) and [Nitro](https://nitro.build/). - -Start avoids being opinionated by only providing the fewest pieces to get you started. -While templates are available that include many of the expected tools, SolidStart itself does not ship with a Router or Metadata library. -Rather, it leaves that open for you to use any library you want. - -SolidStart provides you the ability to render your applications in different ways depending on what is best for your use case. -These include: - -- Client-side rendering (CSR) -- Server-side rendering (SSR) -- Static site generation (SSG) - -A driving principle of SolidStart is that code should be _isomorphic_ — this ensures that code can be written once and executed correctly whether on the client or server. - -## Features - -SolidStart features the following capabilities: - -- **Fine-grained reactivity** — Powered by Solid and its fine-grained reactivity. -- **Isomorphic, nested routing** — The same routes are rendered regardless of whether the page is on the client or server. - Route nesting provides parent-child relationships that simplify application logic. -- **Multiple rendering modes** — Can be used to create CSR, SSR (Sync, Async and Streaming), and SSG applications. -- **Command Line Interface (CLI) and templates** — Provides a CLI and templates to help you get started quickly. -- **Deployment presets** — Provides presets to support deployment to multiple platforms including Netlify, Vercel, AWS, and Cloudflare. - -## Prerequisites - -Before you start using SolidStart, you should have a basic understanding of web development. -This includes knowledge of HTML, CSS, and JavaScript. -With SolidStart being a Solid meta-framework, we recommend learning Solid prior to reading these docs (or at least [taking the Solid tutorial](https://www.solidjs.com/tutorial)). - -## SolidStart 1.0 is here! - -We are actively working on improving the documentation and adding more examples to help you get started. -Documentation is still in beta so content is still being added to the documentation to improve the overall experience of using SolidStart. - -If you experience any issues while using SolidStart, please let us know by [opening an issue in the SolidStart Repo](https://github.com/solidjs/solid-start/issues). -Additionally, if you notice any issues or feel that something is missing in the documentation, please let us know in the [Solid Docs Repo](https://github.com/solidjs/solid-docs-next/issues). diff --git a/src/routes/solid-start/v1/(1)advanced/(0)middleware.mdx b/src/routes/solid-start/v1/(1)advanced/(0)middleware.mdx deleted file mode 100644 index 89ffc58fc..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(0)middleware.mdx +++ /dev/null @@ -1,292 +0,0 @@ ---- -title: Middleware -use_cases: >- - request interception, header management, global data sharing, request - preprocessing, logging, redirects -tags: - - middleware - - headers - - interceptors - - logging - - preprocessing - - locals -version: "1.0" -description: >- - Intercept HTTP requests with middleware for authentication, logging, and - header management. Share request-scoped data across your app. ---- - -Middleware intercepts HTTP requests and responses to perform tasks like authentication, redirection, logging, and more. -It also enables sharing request-scoped data across the application using the `event.locals` object. - -## Common use cases - -Here are some common use cases for middleware: - -- **Request and response header management:** Middleware allows modifying headers to control caching (e.g., `Cache-Control`), improve security (e.g., `Content-Security-Policy`), or implement custom behaviour based on request characteristics. -- **Global data sharing:** The `event.locals` object allows storing and sharing request-scoped data between middleware and any server-side context (e.g., API routes, server-only queries/actions). This is useful for passing information like user authentication status, feature flags, or other request-related data. -- **Server-side redirects:** Middleware can redirect users based on various request properties, such as locale, authentication state, or custom query parameters. -- **Request preprocessing:** Middleware can perform lightweight preprocessing tasks, such as validating tokens or normalizing paths. - -## Limitations - -While middleware is powerful, certain tasks are better handled in other parts of your application for performance, maintainability, or security reasons: - -- **Authorization:** Middleware does _not_ run on every request, especially during client-side navigations. - Relying on it for authorization would create a significant security vulnerability. - As a result, authorization checks should be performed as close to the data source as possible. - This means it within API routes, server-only queries/actions, or other server-side utilities. -- **Heavy computation or long-running processes:** Middleware should be lightweight and execute quickly to avoid impacting performance. - CPU-intensive tasks, long-running processes, or blocking operations (e.g., complex calculations, external API calls) are best handled by dedicated route handlers, server-side utilities, or background jobs. -- **Database operations:** Performing direct database queries within middleware can lead to performance bottlenecks and make your application harder to maintain. - Database interactions should be handled by server-side utilities or route handlers, which will create better management of database connections and handling of potential errors. - -## Basic usage - -Middleware is configured by exporting a configuration object from a dedicated file (e.g., `src/middleware/index.ts`). -This object, created using the [`createMiddleware`](/solid-start/v1/reference/server/create-middleware) function, defines when middleware functions execute throughout the request lifecycle. - -```ts title="src/middleware/index.ts" -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware({ - onRequest: (event) => { - console.log("Request received:", event.request.url); - - event.locals.startTime = Date.now(); - }, - onBeforeResponse: (event) => { - const endTime = Date.now(); - const duration = endTime - event.locals.startTime; - console.log(`Request took ${duration}ms`); - }, -}); -``` - -For SolidStart to recognize the configuration object, the file path is declared in `app.config.ts`: - -```ts title="app.config.ts" -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - middleware: "src/middleware/index.ts", -}); -``` - -## Lifecycle events - -A middleware function executes at specific points in the request lifecycle, using two key events: `onRequest` and `onBeforeResponse`. - -### `onRequest` - -The `onRequest` event is triggered at the beginning of the request lifecycle, before the request is handled by the route handler. -This is the ideal place to: - -- Store request-scoped data in `event.locals` for use in later middleware functions or route handlers. -- Set or modify request headers. -- Perform early redirects. - -### `onBeforeResponse` - -The `onBeforeResponse` event is triggered after a request has been processed by the route handler but before the response is sent to the client. -This is the ideal place to: - -- Set or modify response headers. -- Log response metrics or perform other post-processing tasks. -- Modify the response body. - -## Locals - -In web applications, there's often a need to share request-specific data across different parts of the server-side code. -This data might include user authentication status, trace IDs for debugging, or client metadata (e.g., user agent, geolocation). - -The `event.locals` is a plain JavaScript object that can hold any JavaScript value. -This object provides a temporary, request-scoped storage layer to address this need. -Any data stored within it is only available during the processing of a single HTTP request and is automatically cleared afterward. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware({ - onRequest: (event) => { - event.locals.user = { - name: "John Wick", - }; - event.locals.sayHello = () => { - return "Hello, " + event.locals.user.name; - }; - }, -}); -``` - -Within middleware, `event.locals` can be accessed and modified directly. -Other server-side contexts must use the [`getRequestEvent`](/reference/server-utilities/get-request-event) function to access the `event.locals` object. - -```tsx title="src/routes/index.tsx" -import { getRequestEvent } from "solid-js/web"; -import { query, createAsync } from "@solidjs/router"; - -const getUser = query(async () => { - "use server"; - const event = getRequestEvent(); - return { - name: event?.locals?.user?.name, - greeting: event?.locals?.sayHello(), - }; -}, "user"); - -export default function Page() { - const user = createAsync(() => getUser()); - - return ( -
    -

    Name: {user()?.name}

    - -
    - ); -} -``` - -## Headers - -Request and response headers can be accessed and modified using the `event.request.headers` and `event.response.headers` objects. -These follow the [standard Web API `Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) interface, exposing built-in methods for reading/updating headers. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware({ - onRequest: (event) => { - // Reading client metadata for later use - const userAgent = event.request.headers.get("user-agent"); - // Adding custom headers to request/response - event.request.headers.set("x-custom-request-header", "hello"); - event.response.headers.set("x-custom-response-header1", "hello"); - }, - onBeforeResponse: (event) => { - // Finalizing response headers before sending to client - event.response.headers.set("x-custom-response-header2", "hello"); - }, -}); -``` - -Headers set in `onRequest` are applied **before** the route handler processes the request, allowing downstream middleware or route handlers to override them. -Headers set in `onBeforeResponse` are applied **after** the route handler and are finalized for the client. - -## Cookies - -HTTP cookies are accessible through the `Cookie` request header and `Set-Cookie` response header. -While these headers can be manipulated directly, [Vinxi](https://vinxi.vercel.app), the underlying server toolkit powering SolidStart, provides helpers to simplify cookie management. -See the [Vinxi Cookies documentation](https://vinxi.vercel.app/api/server/cookies.html) for more information. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; -import { getCookie, setCookie } from "vinxi/http"; - -export default createMiddleware({ - onRequest: (event) => { - // Reading a cookie - const theme = getCookie(event.nativeEvent, "theme"); - - // Setting a secure session cookie with expiration - setCookie(event.nativeEvent, "session", "abc123", { - httpOnly: true, - secure: true, - maxAge: 60 * 60 * 24, // 1 day - }); - }, -}); -``` - -## Custom responses - -Returning a value from a middleware function immediately terminates the request processing pipeline and sends the returned value as the response to the client. -This means no further middleware functions or route handlers will be executed. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware({ - onRequest: () => { - return new Response("Unauthorized", { status: 401 }); - }, -}); -``` - -Only [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects can be returned from middleware functions. -Returning any other value will result in an error. - -### Redirects - -[Solid Router](/solid-router) provides the [`redirect` helper function](/solid-router/reference/response-helpers/redirect) which simplifies creating redirect responses. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; -import { redirect } from "@solidjs/router"; - -const REDIRECT_MAP: Record = { - "/signup": "/auth/signup", - "/login": "/auth/login", -}; - -export default createMiddleware({ - onRequest: (event) => { - const { pathname } = new URL(event.request.url); - - // Redirecting legacy routes permanently to new paths - if (pathname in REDIRECT_MAP) { - return redirect(REDIRECT_MAP[pathname], 301); - } - }, -}); -``` - -This example checks the requested path and returns a redirect response if it matches a predefined path. -The 301 status code indicates a permanent redirect. -Other redirect status codes (e.g., 302, 307) are available as needed. - -### JSON responses - -Solid Router provides the [`json` helper function](/solid-router/reference/response-helpers/json) which simplifies sending custom JSON responses. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; -import { json } from "@solidjs/router"; - -export default createMiddleware({ - onRequest: (event) => { - // Rejecting unauthorized API requests with a JSON error - const authHeader = event.request.headers.get("Authorization"); - if (!authHeader) { - return json({ error: "Unauthorized" }, { status: 401 }); - } - }, -}); -``` - -## Chaining middleware functions - -`onRequest` and `onBeforeResponse` options in `createMiddleware` can accept either a single function or an array of middleware functions. -When an array is provided, these functions execute sequentially within the same lifecycle event. -This enables composing smaller, more-focused middleware functions, rather than handling all logic in a single, large middleware function. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; -import { type FetchEvent } from "@solidjs/start/server"; - -function middleware1(event: FetchEvent) { - event.request.headers.set("x-custom-header1", "hello-from-middleware1"); -} - -function middleware2(event: FetchEvent) { - event.request.headers.set("x-custom-header2", "hello-from-middleware2"); -} - -export default createMiddleware({ - onRequest: [middleware1, middleware2], -}); -``` - -The order of middleware functions in the array determines their execution order. -Dependent middleware functions should be placed after the middleware functions they rely on. -For example, authentication middleware should typically run before logging middleware. diff --git a/src/routes/solid-start/v1/(1)advanced/(1)session.mdx b/src/routes/solid-start/v1/(1)advanced/(1)session.mdx deleted file mode 100644 index 3cf6c64ef..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(1)session.mdx +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: Sessions -use_cases: >- - user sessions, authentication state, preferences storage, stateful - interactions, login persistence -tags: - - sessions - - cookies - - authentication - - state - - storage - - persistence -version: "1.0" -description: >- - Manage user sessions with encrypted cookies in SolidStart. Maintain - authentication state and user preferences between requests. ---- - -Sessions allow web applications to maintain state between user requests. -Since HTTP is stateless, each request is treated independently. -Sessions address this by allowing the server to recognize multiple requests from the same user, which is helpful for tracking authentication and preferences. - -## How sessions work - -A session typically involves: - -1. **Session creation**: When tracking is needed (e.g., upon login or first visit), the server creates a session. - This involves generating a unique **session ID** and storing the session data, _encrypted and signed_, within a cookie. -2. **Session cookie transmission**: The server sends a `Set-Cookie` HTTP header. - This instructs the browser to store the session cookie. -3. **Subsequent requests**: The browser automatically includes the session cookie in the `Cookie` HTTP header for requests to the server. -4. **Session retrieval and data access**: For each request, the server checks for the session cookie, retrieves the session data if a cookie is present, then decrypts and verifies the signature of the session data for the application to access and use this data. -5. **Session expiration and destruction**: Sessions typically expire after a period of time or upon user sign-out and the data is removed. - This is done by setting a `Max-Age` attribute on the cookie or by sending a `Set-Cookie` HTTP header with an expired date. - -Most of these steps are automatically managed by the [session helpers](#session-helpers). - -### Database sessions - -For larger applications or when more advanced session management is needed, session data can be stored in a database. -This approach is similar to the cookie-based approach, but with some key differences: - -- The session data is stored in the database, associated with the session ID. -- Only the session ID is stored in the cookie, not the session data. -- The session data is retrieved from the database using the session ID, instead of being retrieved directly from the cookie. -- Upon expiration, in addition to the session cookie, the database record containing the session data is also removed. - -SolidStart does not automatically handle interactions with a database; you need to implement this yourself. - -## Session helpers - -[Vinxi](https://vinxi.vercel.app), the underlying server toolkit powering SolidStart, provides helpers to simplify working with sessions. -It provides a few key session helpers: - -- [`useSession`](https://vinxi.vercel.app/api/server/session.html#usesession): Initializes a session or retrieves the existing session and returns a session object. -- [`getSession`](https://vinxi.vercel.app/api/server/session.html#getsession): Retrieves the current session or initializes a new session. -- [`updateSession`](https://vinxi.vercel.app/api/server/session.html#updatesession): Updates data within the current session. -- [`clearSession`](https://vinxi.vercel.app/api/server/session.html#clearsession): Clears the current session. - -These helpers work _only_ in server-side contexts, such as within server functions and API routes. -This is because session management requires access to server-side resources as well as the ability to get and set HTTP headers. - -For more information, see the [Cookies documentation in the Vinxi docs](https://vinxi.vercel.app/api/server/session.html). - -## Creating a session - -The `useSession` helper is the primary way to create and manage sessions. -It provides a comprehensive interface for all session operations. - -```ts title="src/lib/session.ts" -import { useSession } from "vinxi/http"; - -type SessionData = { - theme: "light" | "dark"; -}; - -export async function useThemeSession() { - "use server"; - const session = await useSession({ - password: process.env.SESSION_SECRET as string, - name: "theme", - }); - - if (!session.data.theme) { - await session.update({ - theme: "light", - }); - } - - return session; -} -``` - -In this example, the `useThemeSession` server function creates a session that stores a user's theme preference. - -`useSession` requires a strong password for encrypting and signing the session cookie. -This password must be at least 32 characters long and should be kept highly secure. -It is strongly recommended to store this password in a [private environment variable](/configuration/environment-variables#private-environment-variables), as shown in the example above, rather than hardcoding it in your source code. - -A password can be generated using the following command: - -```sh frame="none" -openssl rand -base64 32 -``` - -`useSession` adds a `Set-Cookie` HTTP header to the current server response. -By default, the cookie is named `h3`, but can be customized with the `name` option, as shown in the example above. - -## Getting the session data - -The `useSession` helper provides access to the session data from the current request with the `data` property. - -```ts title="src/lib/session.ts" -export async function getThemeSession() { - "use server"; - const session = await useThemeSession(); - - return session.data.theme; -} -``` - -## Updating the session data - -The `useSession` helper provides the `update` method to update the session data from the current request. - -```ts title="src/lib/session.ts" -export async function updateThemeSession(data: SessionData) { - "use server"; - const session = await useThemeSession(); - await session.update(data); -} -``` - -## Clearing the session data - -The `useSession` helper provides the `clear` method to clear the session data from the current request. - -```ts title="src/lib/session.ts" -export async function clearThemeSession() { - "use server"; - const session = await useThemeSession(); - await session.clear(); -} -``` diff --git a/src/routes/solid-start/v1/(1)advanced/(2)request-events.mdx b/src/routes/solid-start/v1/(1)advanced/(2)request-events.mdx deleted file mode 100644 index 3f6954467..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(2)request-events.mdx +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Request events -use_cases: >- - server context access, local data storage, request handling, server functions, - event access -tags: - - events - - server - - context - - locals - - requests - - functions -version: "1.0" -description: >- - Access request events and local context in SolidStart server functions. - Type-safe locals and native event handling for server code. ---- - -Request events in SolidStart are retrieved using the [`getRequestEvent`](/reference/server-utilities/get-request-event) from `@solidjs/web`. -These requests happen anywhere on the server. - -## Locals - -SolidStart uses `event.locals` to pass around a local context where needed. - -When adding fields to `event.locals`, the fields can be typed: - -```tsx title="global.d.ts" -/// -declare module App { - interface RequestEventLocals { - /** - * Declare your getRequestEvent().locals here - */ - } -} -``` - -## nativeEvent - -Sometimes access is still needed to the underlying event from [Vinxi](https://vinxi.vercel.app/). -This can be accessed that using the `.nativeEvent` property, which is the underlying H3Event used, and can be passed to the helpers available in the ecosystem. -Note that Vinxi HTTP helpers _do not_ treeshake so you can only import them in files that do not contain client or isomorphic code. - -Many of these events support Async Local Storage so this may not be needed. diff --git a/src/routes/solid-start/v1/(1)advanced/(3)return-responses.mdx b/src/routes/solid-start/v1/(1)advanced/(3)return-responses.mdx deleted file mode 100644 index 4be635103..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(3)return-responses.mdx +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Returning responses -use_cases: >- - server function responses, error handling, response types, api responses, - typescript typing -tags: - - responses - - server - - functions - - typescript - - errors - - api -version: "1.0" -description: >- - Return typed Response objects from server functions. Handle redirects, - reloads, and JSON responses with proper TypeScript support. ---- - -In SolidStart, it is possible to return a Response object from a server function. -[`solid-router`](/solid-router) knows how to handle certain responses with its [`query`](/solid-router/reference/data-apis/query) and [`action`](/solid-router/reference/data-apis/action) APIs. -For TypeScript, when returning a response using `solid-router`'s `redirect`, `reload`, or `json` helpers, they will not impact the return value of the server function. - -While we suggest depending on the type of the function to handle errors differently, you can always return or throw a response. - -## Examples - -In the following example, the `hello` function will return a value of type `Promise<{ hello: string }>`: - -```tsx -import { json } from "@solidjs/router"; -import { GET } from "@solidjs/start"; - -const hello = GET(async (name: string) => { - "use server"; - return json( - { hello: new Promise((r) => setTimeout(() => r(name), 1000)) }, - { headers: { "cache-control": "max-age=60" } } - ); -}); -``` - -However, in this example, since `redirect` and `reload` return `never` as their type, `getUser` can only return a value of type `Promise`: - -```tsx { 4, 10, 14} -export async function getUser() { - "use server"; - - const session = await getSession(); - const userId = session.data.userId; - if (userId === undefined) return redirect("/login"); - - try { - const user: User = await db.user.findUnique({ where: { id: userId } }); - // throwing can be awkward. - if (!user) return redirect("/login"); - return user; - } catch { - // do stuff - throw redirect("/login"); - } -} -``` diff --git a/src/routes/solid-start/v1/(1)advanced/(4)serialization.mdx b/src/routes/solid-start/v1/(1)advanced/(4)serialization.mdx deleted file mode 100644 index bd7629653..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(4)serialization.mdx +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: Serialization -use_cases: >- - server function payloads, data transfer, csp, security, performance -tags: - - serialization - - server-functions - - csp - - security - - performance -version: "1.0" -description: >- - Understand how SolidStart serializes server function payloads, supported - types, and CSP tradeoffs. ---- - -SolidStart serializes server function arguments and return values so they can travel between server and client. It uses Seroval under the hood and streams payloads to keep responses responsive. - -## Configuration - -Configure serialization in your `app.config.ts` with `defineConfig`: - -```tsx tab title="v1" -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - serialization: { - mode: "js", - }, -}); -``` - -```tsx tab title="v2" -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start"; - -export default defineConfig({ - plugins: [ - solidStart({ - serialization: { - mode: "json", - }, - }), - ], -}); -``` - -See the full config reference in [`defineConfig`](/solid-start/v1/reference/config/define-config#serialization). - -## Modes - -- `json`: Uses `JSON.parse` on the client. Best for strict CSP because it avoids `eval`. Payloads can be slightly larger. -- `js`: Uses Seroval's JS serializer for smaller payloads and better performance, but it requires `unsafe-eval` in CSP. - -:::caution[v2 Breaking Change: Defaults] -SolidStart v1 defaults to `js` for backwards compatibility. SolidStart v2 defaults to `json` for CSP compatibility. -::: - -## Supported types (default) - -SolidStart enables Seroval plus a default set of web platform plugins. These plugins add support for: - -- `AbortSignal`, `CustomEvent`, `DOMException`, `Event` -- `FormData`, `Headers`, `ReadableStream` -- `Request`, `Response` -- `URL`, `URLSearchParams` - -Seroval supports additional value types. The compatibility list is broader than what SolidStart enables by default, so treat it as a superset. See the [Seroval compatibility docs](https://github.com/lxsmnsyc/seroval/blob/main/docs/COMPATIBILITY.md). - -## Limits and exclusions - -- `RegExp` is disabled by default. -- JSON mode enforces a maximum serialization depth of 64. If you exceed this, flatten the structure or return a simpler payload. - -## Related guidance - -- Configure modes and defaults in [`defineConfig`](/solid-start/v1/reference/config/define-config#serialization). -- CSP implications and nonce examples live in the [Security guide](/solid-start/v1/guides/security#content-security-policy-csp). diff --git a/src/routes/solid-start/v1/(1)advanced/(5)auth.mdx b/src/routes/solid-start/v1/(1)advanced/(5)auth.mdx deleted file mode 100644 index b0d2f2eb6..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(5)auth.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Auth -use_cases: >- - user authentication, protected routes, authorization checks, secure data - access, login systems -tags: - - authentication - - authorization - - security - - protected - - login - - users -version: "1.0" -description: >- - Implement authentication and protected routes in SolidStart. Secure sensitive - resources and handle user authorization properly. ---- - -Server functions can be used to protect sensitive resources like user data. - -```tsx -"use server"; - -async function getPrivatePosts() { - const user = await getUser(); - if (!user) { - return null; // or throw an error - } - - return db.getPosts({ userId: user.id, private: true }); -} -``` - -The `getUser` function can be [implemented using sessions](/solid-start/v1/advanced/session). - -## Protected Routes - -Routes can be protected by checking the user or session object during data fetching. -This example uses [Solid Router](/solid-router). - -```tsx -const getPrivatePosts = query(async function () { - "use server"; - const user = await getUser(); - if (!user) { - throw redirect("/login"); - } - - return db.getPosts({ userId: user.id, private: true }); -}); - -export default function Page() { - const posts = createAsync(() => getPrivatePosts(), { deferStream: true }); -} -``` - -Once the user hits this route, the router will attempt to fetch `getPrivatePosts` data. -If the user is not signed in, `getPrivatePosts` will throw and the router will redirect to the login page. - -To prevent errors when opening the page directly, set `deferStream: true`. -This would ensure `getPrivatePosts` resolves before the page loads since server-side redirects cannot occur after streaming has started. diff --git a/src/routes/solid-start/v1/(1)advanced/(6)websocket.mdx b/src/routes/solid-start/v1/(1)advanced/(6)websocket.mdx deleted file mode 100644 index 11ca0a5dc..000000000 --- a/src/routes/solid-start/v1/(1)advanced/(6)websocket.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: WebSocket endpoint -use_cases: >- - real-time updates, chat applications, live notifications, multiplayer games, - collaborative editing, streaming data -tags: - - websocket - - real-time - - streaming - - experimental - - server - - events -version: "1.0" -description: >- - Set up WebSocket endpoints in SolidStart for real-time bidirectional - communication. Handle connections, messages, and events. ---- - -WebSocket endpoint may be included by passing the ws handler file you specify in your start config. -Note that this feature is [experimental on the Nitro server](https://nitro.build/guide/websocket#opt-in-to-the-experimental-feature) and its config may change in future releases of SolidStart. Use it with caution. - -```ts title="./app.config.ts" -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - experimental: { - websocket: true, - }, - }, -}).addRouter({ - name: "ws", - type: "http", - handler: "./src/ws.ts", - target: "server", - base: "/ws", -}); -``` - -Inside the ws file, you can export an eventHandler function to manage WebSocket connections and events: - -```tsx title="./src/ws.ts" -import { eventHandler } from "vinxi/http"; - -export default eventHandler({ - handler() {}, - websocket: { - async open(peer) { - console.log("open", peer.id, peer.url); - }, - async message(peer, msg) { - const message = msg.text(); - console.log("msg", peer.id, peer.url, message); - }, - async close(peer, details) { - console.log("close", peer.id, peer.url); - }, - async error(peer, error) { - console.log("error", peer.id, peer.url, error); - }, - }, -}); -``` diff --git a/src/routes/solid-start/v1/(1)getting-started.mdx b/src/routes/solid-start/v1/(1)getting-started.mdx deleted file mode 100644 index 93c782a00..000000000 --- a/src/routes/solid-start/v1/(1)getting-started.mdx +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: Getting started -use_cases: >- - new project, initial setup, project creation, starter template, first app, - quick start, bootstrapping -tags: - - setup - - installation - - starter - - template - - quickstart - - init -version: "1.0" -description: >- - Start your first SolidStart project with templates and step-by-step setup. - Create, configure, and run your Solid application. ---- - -The easiest way to get started with Solid is to use the SolidStart starter. -This starter contains a collection of templates that can be used to quickly bootstrap a new Solid application. - -**1. Install SolidStart** - -To start a new project you can initialize SolidStart with the following command: - -```package-create -solid -``` - -This will create a new directory for your project based on the name you enter. - -**2. Choose a template** - -When you run the command above, SolidStart will prompt you to choose a template for your new application. -You can see a [list of these options in the templates repository](https://github.com/solidjs/templates/tree/main/solid-start-v1). - -```bash frame="terminal" -◆ Which template would you like to use? -│ ● basic -│ ○ bare -│ ○ with-solidbase -│ ○ with-auth -│ ○ with-authjs -│ ○ with-drizzle -│ ○ with-mdx -│ ○ with-prisma -│ ○ with-solid-styled -│ ○ with-tailwindcss -│ ... -└ -``` - -Following the prompts, you might be asked questions like whether you want to use Server Side Rendering or TypeScript. -Choose your desired options to continue. - -**3. Install dependencies** - -Once you have chosen your template and configuration options, you can navigate to the directory you created and run the following command to install dependencies: - -```package-install-local - -``` - -After this command has finished, your new SolidStart application is ready to go! - -**4. Run your application** - -To run your application locally, you can use the following command: - -```package-run -dev -``` - -Your application should now be running locally on port 3000. -You can view it by navigating to [http://localhost:3000](http://localhost:3000). - -:::note -SolidStart uses [Vinxi](https://vinxi.vercel.app/) both for starting a development server with [Vite](https://vitejs.dev/) and for building and starting a production server with [Nitro](https://nitro.build/). - - When you run your application, you are actually running `vinxi dev` under the hood. - - You can read more about the [Vinxi CLI and how it is configured in the Vinxi documentation](https://vinxi.vercel.app/api/cli.html). - -::: - -## Project files - -SolidStart will create a new directory for your project, and populate it with the necessary files and directories to get you started. -These files and directories are the basic structure of a SolidStart application, and you can modify them to suit your needs. -The default structure of a SolidStart application looks like this: - -``` -public/ -src/ -├── routes/ -│ ├── index.tsx -├── entry-client.tsx -├── entry-server.tsx -├── app.tsx -``` - -**Note:** Depending on the configuration options you chose when creating your project, your file structure may look slightly different. -For example, if you chose to use JavaScript rather than TypeScript, your file extensions will be `.jsx` instead of `.tsx`. - -Each directory and file in this structure serves a specific purpose in your SolidStart application: - -- `public/` - contains the publicly-accessible assets for your application. - This is where images, fonts, and other files that you want to be accessible to the public should be placed. -- `src/` - where your Start application code will live. - It is aliased to `~/` for importing in your code. -- `src/routes/` - any files or pages will be located in this directory. - You can learn more about the [`routes` folder in the routing section](/solid-start/v1/building-your-application/routing). -- [`src/entry-client.tsx`](/solid-start/v1/reference/entrypoints/entry-client) - this file is what loads and _hydrates_ the JavaScript for our application on the client side (in browser). - In most cases, you will **not** need to modify this file. -- [`src/entry-server.tsx`](/solid-start/v1/reference/entrypoints/entry-server) - this file will handle requests on the server. - Like `entry-client.tsx`, in most cases you will **not** need to modify this file. -- [`app.tsx`](/solid-start/v1/reference/entrypoints/app) - this is the HTML root of your application both for client and server rendering. You can think of this as the shell inside which your application will be rendered. diff --git a/src/routes/solid-start/v1/(2)guides/(0)security.mdx b/src/routes/solid-start/v1/(2)guides/(0)security.mdx deleted file mode 100644 index 46ae9f1a2..000000000 --- a/src/routes/solid-start/v1/(2)guides/(0)security.mdx +++ /dev/null @@ -1,217 +0,0 @@ ---- -title: Security -use_cases: >- - production apps, user input handling, authentication, public apis, preventing - attacks, secure deployments, compliance -tags: - - security - - xss - - csrf - - cors - - csp - - middleware - - protection -version: "1.0" -description: >- - Secure your SolidStart apps against XSS, CSRF attacks. Configure CSP headers, - CORS policies, and implement security best practices. ---- - -## XSS (Cross Site Scripting) - -Solid automatically escapes values passed to JSX expressions to reduce the risk of XSS attacks. -However, this protection does not apply when using [`innerHTML`](/reference/jsx-attributes/innerhtml). - -To protect your application from XSS attacks: - -- Set a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). -- Validate and sanitize user inputs, especially form inputs on the server and client. -- Avoid using `innerHTML` when possible. - If necessary, make sure to sanitize user-supplied data with libraries such as [DOMPurify](https://github.com/cure53/DOMPurify). -- Sanitize attributes containing user-supplied data within `
    }> - {(post) =>
  • {post.title}
  • }
    - -
- ); -} -``` - -```jsx tab title="JavaScript" {14} {16} -// src/routes/index.jsx -import { Suspense, For } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); -}, "posts"); - -export default function Page() { - const posts = createAsync(() => getPosts()); - return ( -
    - Loading...}> - {(post) =>
  • {post.title}
  • }
    -
    -
- ); -} -``` - -## Handling errors - -To show a fallback UI if the data fetching fails: - -1. Import [`ErrorBoundary`](/reference/components/error-boundary) from `solid-js`. -2. Wrap the data rendering in ``, and use the `fallback` prop to show a component if an error occurs. - -```tsx tab title="TypeScript" {14} {18} -// src/routes/index.tsx -import { ErrorBoundary, Suspense, For } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); -}, "posts"); - -export default function Page() { - const posts = createAsync(() => getPosts()); - return ( -
    - Something went wrong!}> - Loading...}> - {(post) =>
  • {post.title}
  • }
    -
    -
    -
- ); -} -``` - -```jsx tab title="JavaScript" {14} {18} -// src/routes/index.jsx -import { ErrorBoundary, Suspense, For } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); -}, "posts"); - -export default function Page() { - const posts = createAsync(() => getPosts()); - return ( -
    - Something went wrong!}> - Loading...}> - {(post) =>
  • {post.title}
  • }
    -
    -
    -
- ); -} -``` - -## Preloading data - -To preload data before a route renders: - -1. Export a `route` object with a [`preload`](/solid-router/reference/preload-functions/preload) function. -2. Run your query inside the `preload` function. -3. Use the query as usual in your component. - -```tsx tab title="TypeScript" {10-12} -// src/routes/index.tsx -import { ErrorBoundary } from "solid-js"; -import { query, createAsync, type RouteDefinition } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); -}, "posts"); - -export const route = { - preload: () => getPosts(), -} satisfies RouteDefinition; - -export default function Page() { - const post = createAsync(() => getPosts()); - return ( -
- Something went wrong!
}> -

{post().title}

-
- - ); -} -``` - -```jsx tab title="JavaScript" {10-12} -// src/routes/index.jsx -import { ErrorBoundary } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); -}, "posts"); - -export const route = { - preload: () => getPosts(), -}; - -export default function Page() { - const post = createAsync(() => getPosts()); - return ( -
- Something went wrong!
}> -

{post().title}

- - - ); -} -``` - -## Passing parameters to queries - -When creating a query that accepts parameters, define your query function to take any number of parameters: - -```tsx tab title="TypeScript" {5} {11} {16} -// src/routes/posts/[id]/index.tsx -import { ErrorBoundary } from "solid-js"; -import { query, createAsync, type RouteDefinition } from "@solidjs/router"; - -const getPost = query(async (id: string) => { - const post = await fetch(`https://my-api.com/posts/${id}`); - return await post.json(); -}, "post"); - -export const route = { - preload: ({ params }) => getPost(params.id), -} satisfies RouteDefinition; - -export default function Page() { - const postId = 1; - const post = createAsync(() => getPost(postId)); - return ( -
- Something went wrong!
}> -

{post().title}

- - - ); -} -``` - -```jsx tab title="JavaScript" {5} {11} {16} -// src/routes/posts/[id]/index.jsx -import { ErrorBoundary } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; - -const getPost = query(async (id) => { - const post = await fetch(`https://my-api.com/posts/${id}`); - return await post.json(); -}, "post"); - -export const route = { - preload: ({ params }) => getPost(params.id), -}; - -export default function Page() { - const postId = 1; - const post = createAsync(() => getPost(postId)); - return ( -
- Something went wrong!
}> -

{post().title}

- - - ); -} -``` - -## Using a database or an ORM - -To safely interact with your database or ORM in a query, use a [server function](/solid-start/v1/reference/server/use-server): - -```tsx tab title="TypeScript" {7-8} -// src/routes/index.tsx -import { For, ErrorBoundary } from "solid-js"; -import { query, createAsync, type RouteDefinition } from "@solidjs/router"; -import { db } from "~/lib/db"; - -const getPosts = query(async () => { - "use server"; - return await db.from("posts").select(); -}, "posts"); - -export const route = { - preload: () => getPosts(), -} satisfies RouteDefinition; - -export default function Page() { - const posts = createAsync(() => getPosts()); - return ( -
    - Something went wrong!}> - {(post) =>
  • {post.title}
  • }
    -
    -
- ); -} -``` - -```jsx tab title="JavaScript" {7-8} -// src/routes/index.jsx -import { For, ErrorBoundary } from "solid-js"; -import { query, createAsync } from "@solidjs/router"; -import { db } from "~/lib/db"; - -const getPosts = query(async () => { - "use server"; - return await db.from("posts").select(); -}, "posts"); - -export const route = { - preload: () => getPosts(), -}; - -export default function Page() { - const posts = createAsync(() => getPosts()); - return ( -
    - Something went wrong!}> - {(post) =>
  • {post.title}
  • }
    -
    -
- ); -} -``` - -## Fetching data on the client - -To fetch data only on the client, use the [`createResource`](/reference/basic-reactivity/create-resource) primitive: - -```tsx tab title="TypeScript" {5-8} {13} -// src/routes/index.tsx -import { createResource, ErrorBoundary, Suspense, For } from "solid-js"; - -export default function Page() { - const [posts] = createResource(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); - }); - return ( -
    - Something went wrong!}> - Loading...}> - {(post) =>
  • {post.title}
  • }
    -
    -
    -
- ); -} -``` - -```jsx tab title="JavaScript" {5-8} {13} -// src/routes/index.jsx -import { createResource, ErrorBoundary, Suspense, For } from "solid-js"; - -export default function Page() { - const [posts] = createResource(async () => { - const posts = await fetch("https://my-api.com/posts"); - return await posts.json(); - }); - return ( -
    - Something went wrong!}> - Loading...}> - {(post) =>
  • {post.title}
  • }
    -
    -
    -
- ); -} -``` - -See the [`createResource`](/reference/basic-reactivity/create-resource) API reference for more information. - -:::note[Advanced Data Handling] -For advanced features like automatic background re-fetching or infinite queries, you can use [TanStack Query](https://tanstack.com/query/latest/docs/framework/solid/overview). -::: diff --git a/src/routes/solid-start/v1/(2)guides/(2)data-mutation.mdx b/src/routes/solid-start/v1/(2)guides/(2)data-mutation.mdx deleted file mode 100644 index 5a9406e27..000000000 --- a/src/routes/solid-start/v1/(2)guides/(2)data-mutation.mdx +++ /dev/null @@ -1,557 +0,0 @@ ---- -title: Data mutation -use_cases: >- - form submission, data updates, crud operations, user input handling, database - writes, api posts, validation, optimistic ui -tags: - - forms - - actions - - mutations - - validation - - database - - api - - crud -version: "1.0" -description: >- - Learn how to handle form submissions, validate data, and perform mutations - with SolidStart actions. Complete guide with examples. ---- - -This guide provides practical examples of using actions to mutate data in SolidStart. - -## Handling form submission - -To handle [`
`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) submissions with an action: - -1. Ensure the action has a unique name. - See the [Action API reference](/solid-router/reference/data-apis/action#notes-of-form-implementation-and-ssr) for more information. -2. Pass the action to the `` element using the `action` prop. -3. Ensure the `` element uses the `post` method for submission. -4. Use the [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData) object in the action to extract field data using the native `FormData` methods. - -```tsx tab title="TypeScript" {4-10} {14} -// src/routes/index.tsx -import { action } from "@solidjs/router"; - -const addPost = action(async (formData: FormData) => { - const title = formData.get("title") as string; - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - return ( - - - -
- ); -} -``` - -```jsx tab title="JavaScript" {4-10} {14} -// src/routes/index.jsx -import { action } from "@solidjs/router"; - -const addPost = action(async (formData) => { - const title = formData.get("title"); - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - return ( -
- - -
- ); -} -``` - -## Passing additional arguments - -To pass additional arguments to your action, use the `with` method: - -```tsx tab title="TypeScript" {4} {15} -// src/routes/index.tsx -import { action } from "@solidjs/router"; - -const addPost = action(async (userId: number, formData: FormData) => { - const title = formData.get("title") as string; - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ userId, title }), - }); -}, "addPost"); - -export default function Page() { - const userId = 1; - return ( -
- - -
- ); -} -``` - -```jsx tab title="JavaScript" {4} {15} -// src/routes/index.jsx -import { action } from "@solidjs/router"; - -const addPost = action(async (userId, formData) => { - const title = formData.get("title"); - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ userId, title }), - }); -}, "addPost"); - -export default function Page() { - const userId = 1; - return ( -
- - -
- ); -} -``` - -## Showing pending UI - -To display a pending UI during action execution: - -1. Import [`useSubmission`](/solid-router/reference/data-apis/use-submission) from `@solidjs/router`. -2. Call `useSubmission` with your action, and use the returned `pending` property to display pending UI. - -```tsx tab title="TypeScript" {13} {17-19} -// src/routes/index.tsx -import { action, useSubmission } from "@solidjs/router"; - -const addPost = action(async (formData: FormData) => { - const title = formData.get("title") as string; - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const submission = useSubmission(addPost); - return ( -
- - -
- ); -} -``` - -```jsx tab title="JavaScript" {13} {17-19} -// src/routes/index.jsx -import { action, useSubmission } from "@solidjs/router"; - -const addPost = action(async (formData) => { - const title = formData.get("title"); - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const submission = useSubmission(addPost); - return ( -
- - -
- ); -} -``` - -## Handling errors - -To handle errors that occur within an action: - -1. Import [`useSubmission`](/solid-router/reference/data-apis/use-submission) from `@solidjs/router`. -2. Call `useSubmission` with your action, and use the returned `error` property to handle the error. - -```tsx tab title="TypeScript" {14} {17-19} -// src/routes/index.tsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const addPost = action(async (formData: FormData) => { - const title = formData.get("title") as string; - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const submission = useSubmission(addPost); - return ( -
- -

{submission.error.message}

-
- - -
- ); -} -``` - -```jsx tab title="JavaScript" {14} {17-19} -// src/routes/index.jsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const addPost = action(async (formData) => { - const title = formData.get("title"); - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const submission = useSubmission(addPost); - return ( -
- -

{submission.error.message}

-
- - -
- ); -} -``` - -## Validating form fields - -To validate form fields in an action: - -1. Add validation logic in your action and return validation errors if the data is invalid. -2. Import [`useSubmission`](/solid-router/reference/data-apis/use-submission) from `@solidjs/router`. -3. Call `useSubmission` with your action, and use the returned `result` property to handle the errors. - -```tsx tab title="TypeScript" {7-11} {19} {23-25} -// src/routes/index.tsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const addPost = action(async (formData: FormData) => { - const title = formData.get("title") as string; - if (!title || title.length < 2) { - return { - error: "Title must be at least 2 characters", - }; - } - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const submission = useSubmission(addPost); - return ( -
- - -

{submission.result?.error}

-
- -
- ); -} -``` - -```jsx tab title="JavaScript" {7-11} {19} {23-25} -// src/routes/index.jsx -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const addPost = action(async (formData) => { - const title = formData.get("title"); - if (!title || title.length < 2) { - return { - error: "Title must be at least 2 characters", - }; - } - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const submission = useSubmission(addPost); - return ( -
- - -

{submission.result?.error}

-
- -
- ); -} -``` - -## Showing optimistic UI - -To update the UI before the server responds: - -1. Import [`useSubmission`](/solid-router/reference/data-apis/use-submission) from `@solidjs/router`. -2. Call `useSubmission` with your action, and use the returned `pending` and `input` properties to display optimistic UI. - -```tsx tab title="TypeScript" {20} {29-31} -// src/routes/index.tsx -import { For, Show } from "solid-js"; -import { action, useSubmission, query, createAsync } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/blog"); - return await posts.json(); -}, "posts"); - -const addPost = action(async (formData: FormData) => { - const title = formData.get("title"); - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const posts = createAsync(() => getPosts()); - const submission = useSubmission(addPost); - return ( -
-
- - -
-
    - {(post) =>
  • {post.title}
  • }
    - - {submission.input?.[0]?.get("title")?.toString()} - -
-
- ); -} -``` - -```jsx tab title="JavaScript" {20} {29-31} -// src/routes/index.jsx -import { For, Show } from "solid-js"; -import { action, useSubmission, query, createAsync } from "@solidjs/router"; - -const getPosts = query(async () => { - const posts = await fetch("https://my-api.com/blog"); - return await posts.json(); -}, "posts"); - -const addPost = action(async (formData) => { - const title = formData.get("title"); - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const posts = createAsync(() => getPosts()); - const submission = useSubmission(addPost); - return ( -
-
- - -
-
    - {(post) =>
  • {post.title}
  • }
    - - {submission.input?.[0]?.get("title")?.toString()} - -
-
- ); -} -``` - -:::note[Multiple Submissions] -If you want to display optimistic UI for multiple concurrent submissions, you can use the [`useSubmissions`](/solid-router/reference/data-apis/use-submissions) primitive. -::: - -## Redirecting - -To redirect users to a different route within an action: - -1. Import [`redirect`](/solid-router/reference/response-helpers/redirect) from `@solidjs/router`. -2. Call `redirect` with the route you want to navigate to, and throw its response. - -```tsx tab title="TypeScript" {11} -// src/routes/index.tsx -import { action, redirect } from "@solidjs/router"; - -const addPost = action(async (formData: FormData) => { - const title = formData.get("title") as string; - const response = await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); - const post = await response.json(); - throw redirect(`/posts/${post.id}`); -}, "addPost"); - -export default function Page() { - return ( -
- - -
- ); -} -``` - -```jsx tab title="JavaScript" {11} -// src/routes/index.jsx -import { action, redirect } from "@solidjs/router"; - -const addPost = action(async (formData) => { - const title = formData.get("title"); - const response = await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); - const post = await response.json(); - throw redirect(`/posts/${post.id}`); -}, "addPost"); - -export default function Page() { - return ( -
- - -
- ); -} -``` - -## Using a database or an ORM - -To safely interact with your database or ORM in an action, ensure it's server-only by adding [`"use server"`](/solid-start/v1/reference/server/use-server) as the first line of your action: - -```tsx tab title="TypeScript" {6} -// src/routes/index.tsx -import { action } from "@solidjs/router"; -import { db } from "~/lib/db"; - -const addPost = action(async (formData: FormData) => { - "use server"; - const title = formData.get("title") as string; - await db.insert("posts").values({ title }); -}, "addPost"); - -export default function Page() { - return ( -
- - -
- ); -} -``` - -```jsx tab title="JavaScript" {6} -// src/routes/index.jsx -import { action } from "@solidjs/router"; -import { db } from "~/lib/db"; - -const addPost = action(async (formData) => { - "use server"; - const title = formData.get("title"); - await db.insert("posts").values({ title }); -}, "addPost"); - -export default function Page() { - return ( -
- - -
- ); -} -``` - -## Triggering an action programmatically - -To programmatically trigger an action: - -1. Import [`useAction`](/solid-router/reference/data-apis/use-action) from `@solidjs/router`. -2. Call `useAction` with your action, and use the returned function to trigger the action. - -```tsx tab title="TypeScript" {14} {18} -// src/routes/index.tsx -import { createSignal } from "solid-js"; -import { action, useAction } from "@solidjs/router"; - -const addPost = action(async (title: string) => { - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const [title, setTitle] = createSignal(""); - const addPostAction = useAction(addPost); - return ( -
- setTitle(e.target.value)} /> - -
- ); -} -``` - -```jsx tab title="JavaScript" {14} {18} -// src/routes/index.jsx -import { createSignal } from "solid-js"; -import { action, useAction } from "@solidjs/router"; - -const addPost = action(async (title) => { - await fetch("https://my-api.com/posts", { - method: "POST", - body: JSON.stringify({ title }), - }); -}, "addPost"); - -export default function Page() { - const [title, setTitle] = createSignal(""); - const addPostAction = useAction(addPost); - return ( -
- setTitle(e.target.value)} /> - -
- ); -} -``` diff --git a/src/routes/solid-start/v1/(2)guides/(3)service-workers.mdx b/src/routes/solid-start/v1/(2)guides/(3)service-workers.mdx deleted file mode 100644 index e15aeb6f9..000000000 --- a/src/routes/solid-start/v1/(2)guides/(3)service-workers.mdx +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Service workers -use_cases: >- - offline support, pwa, caching, background sync, push notifications, - performance optimization -tags: - - service-workers - - pwa - - offline - - caching - - performance -version: "1.0" -description: >- - Register and configure service workers in SolidStart for offline support, - caching strategies, and progressive web app features. ---- - -To register a service worker: - -1. Place your service-worker file in the `public` directory (e.g., `public/sw.js`), making it available at the root URL (`/sw.js`). -2. Add registration logic to the `entry-client.tsx` file. - -```tsx {6-11} title="src/entry-client.tsx" -// @refresh reload -import { mount, StartClient } from "@solidjs/start/client"; - -mount(() => , document.getElementById("app")!); - -if ("serviceWorker" in navigator && import.meta.env.PROD) { - window.addEventListener("load", () => { - navigator.serviceWorker.register("/sw.js"); - }); -} -``` diff --git a/src/routes/solid-start/v1/(2)guides/(4)background-tasks.mdx b/src/routes/solid-start/v1/(2)guides/(4)background-tasks.mdx deleted file mode 100644 index 68313565a..000000000 --- a/src/routes/solid-start/v1/(2)guides/(4)background-tasks.mdx +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: Background tasks -use_cases: >- - background tasks, scheduled jobs, periodic jobs, cron, automation -tags: - - cron - - nitro - - tasks - - solidstart -version: "1.0" -description: >- - Schedule background tasks in SolidStart using Nitro's Tasks API for periodic - jobs and automated server-side operations. ---- - -SolidStart supports scheduled background tasks through [Nitro's Tasks API](https://nitro.build/guide/tasks). -Background tasks are server-side operations that run independently of the user request-response cycle. -They are typically used for time-consuming or periodic work like data processing or maintenance jobs. -These tasks execute on the server and can be triggered on a schedule or programmatically. - -For details on which hosting platforms support scheduled tasks (including platform-specific native integrations like Cloudflare Cron Triggers and Vercel Cron Jobs), see the [Nitro documentation on platform support](https://nitro.build/docs/tasks#platform-support). - -## Configuration - -Tasks are an experimental feature and must be explicitly enabled: - -```ts title="app.config.ts" -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - experimental: { - tasks: true, - }, - }, -}); -``` - -## Creating a task - -To create a task: - -1. Create a task file in the `tasks/` directory at your project root (not inside `src/`). -2. Use the `defineTask` function to define a task and `export default` the result. - -```ts title="tasks/cleanup-sessions.ts" -import { defineTask } from "nitropack/runtime"; - -export default defineTask({ - meta: { - name: "cleanup-sessions", - description: "Remove stale database sessions", - }, - async run() { - // Delete expired sessions older than 7 days - const deletedSessions = await db.session.deleteMany({ - where: { - lastActive: { - lt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), - }, - }, - }); - console.log(`Cleanup complete: ${deletedSessions.count} sessions deleted`); - return { result: { deletedSessions } }; - }, -}); -``` - -:::note -`nitropack` is a transitive dependency of SolidStart. -If TypeScript can't resolve the import, add it as a dev dependency: - -```package-install-dev -nitropack -``` - -::: - -Refer to the [Nitro documentation](https://nitro.build/docs/tasks#task-interface) to learn more about `defineTask`. - -## Scheduling tasks - -To run a task automatically on a schedule, add a `scheduledTasks` object to your `app.config.ts`. -The key is a cron expression, and the value is the task name or an array of task names. -When multiple tasks are assigned to the same cron expression, they run in parallel. - -```ts title="app.config.ts" -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - experimental: { - tasks: true, - }, - scheduledTasks: { - // Run at midnight every day - "0 0 * * *": "cleanup-sessions", - }, - }, -}); -``` - -:::tip -You can use [crontab.guru](https://crontab.guru/) to help generate and understand cron patterns. -::: - -## Running tasks on demand - -You can trigger a task manually via the Nitro task endpoint during development using a `GET` request: - -```sh -curl http://localhost:3000/_nitro/tasks/cleanup-sessions -``` - -This is useful for testing your task logic without waiting for the scheduled time. diff --git a/src/routes/solid-start/v1/reference/client/client-only.mdx b/src/routes/solid-start/v1/reference/client/client-only.mdx deleted file mode 100644 index abc85272c..000000000 --- a/src/routes/solid-start/v1/reference/client/client-only.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -title: clientOnly -use_cases: >- - client-only components, browser-only imports, fallback rendering -tags: - - client - - component - - lazy -version: "1.0" -description: >- - clientOnly creates a component that renders only on the client. ---- - -`clientOnly` wraps an async component import and returns a component that renders its fallback on the server. - -## Import - -```tsx -import { clientOnly } from "@solidjs/start"; -``` - -## Type - -```tsx -function clientOnly>( - fn: () => Promise<{ default: T }>, - options?: { lazy?: boolean } -): (props: ComponentProps & { fallback?: JSX.Element }) => any; -``` - -## Parameters - -### `fn` - -- **Type:** `() => Promise<{ default: T }>` -- **Required:** Yes - -Function that imports the client component. - -### `options` - -- **Type:** `{ lazy?: boolean }` -- **Default:** `{}` -- **Required:** No - -Loading options with the following properties: - -### `lazy` - -- **Type:** `boolean` -- **Required:** No - -Controls whether the component import is loaded from inside the returned component. - -## Return value - -- **Type:** `(props: ComponentProps & { fallback?: JSX.Element }) => any` - -Returns a component for the imported default export. - -## Behavior - -- On the server, the returned component renders `props.fallback`. -- Client rendering loads `fn` immediately unless `options.lazy` is truthy. -- `fallback` is split from the remaining props before the loaded component renders. -- During hydration, rendering waits until mount. - -## Examples - -### Basic usage - -```tsx -import { clientOnly } from "@solidjs/start"; - -const Map = clientOnly(() => import("./Map"), { - lazy: true, -}); - -export default function Page() { - return Loading map...

} />; -} -``` diff --git a/src/routes/solid-start/v1/reference/client/mount.mdx b/src/routes/solid-start/v1/reference/client/mount.mdx deleted file mode 100644 index a42320afe..000000000 --- a/src/routes/solid-start/v1/reference/client/mount.mdx +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: mount -use_cases: >- - client entry, hydration, app mounting -tags: - - client - - hydration - - entry -version: "1.0" -description: >- - mount hydrates the client entry. ---- - -`mount` hydrates a client entry and includes island hydration handling. - -## Import - -```tsx -import { mount } from "@solidjs/start/client"; -``` - -## Type - -```tsx -function mount( - fn: () => JSX.Element, - el: MountableElement -): (() => void) | undefined; -``` - -## Parameters - -### `fn` - -- **Type:** `() => JSX.Element` -- **Required:** Yes - -Function that returns the client app element. - -### `el` - -- **Type:** `MountableElement` -- **Required:** Yes - -Element used as the hydration root. - -## Return value - -- **Type:** `(() => void) | undefined` - -Returns the value from [`hydrate`](/reference/rendering/hydrate) for non-island builds. In island builds, it returns `undefined`. - -## Behavior - -- In non-island builds, [`hydrate`](/reference/rendering/hydrate) is called with `fn` and `el`. -- Island builds hydrate `solid-island[data-hk]` elements and do not call `hydrate(fn, el)`. -- CSS links listed in `data-css` are loaded when a matching `link[href]` is not already present. -- Islands with `data-when="idle"` hydrate through `requestIdleCallback` when it exists. - -## Examples - -### Basic usage - -```tsx -import { mount, StartClient } from "@solidjs/start/client"; - -mount(() => , document.getElementById("app")!); -``` - -## Related - -- [`hydrate`](/reference/rendering/hydrate) -- [`StartClient`](/solid-start/v1/reference/client/start-client) diff --git a/src/routes/solid-start/v1/reference/client/start-client.mdx b/src/routes/solid-start/v1/reference/client/start-client.mdx deleted file mode 100644 index 3d7c81e63..000000000 --- a/src/routes/solid-start/v1/reference/client/start-client.mdx +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: StartClient -use_cases: >- - client entry, app hydration, client root -tags: - - client - - entry - - component -version: "1.0" -description: >- - StartClient renders the app on the client. ---- - -`StartClient` is a component that renders the generated app inside the client error boundary. - -## Import - -```tsx -import { StartClient } from "@solidjs/start/client"; -``` - -## Type - -```tsx -function StartClient(): JSX.Element; -``` - -## Parameters - -`StartClient` takes no arguments. - -## Return value - -- **Type:** `JSX.Element` - -Returns the client app element. - -## Behavior - -- Renders the `#start/app` module. -- Wraps the app in the shared `ErrorBoundary`. - -## Examples - -### Basic usage - -```tsx -import { mount, StartClient } from "@solidjs/start/client"; - -mount(() => , document.getElementById("app")!); -``` - -## Related - -- [`mount`](/solid-start/v1/reference/client/mount) diff --git a/src/routes/solid-start/v1/reference/config/define-config.mdx b/src/routes/solid-start/v1/reference/config/define-config.mdx deleted file mode 100644 index ff80439e4..000000000 --- a/src/routes/solid-start/v1/reference/config/define-config.mdx +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: defineConfig -use_cases: >- - app configuration, deployment setup, build optimization, platform targeting, - vite plugins, nitro presets -tags: - - configuration - - vite - - nitro - - deployment - - build - - plugins -version: "1.0" -description: >- - Configure SolidStart apps with defineConfig. Set up Vite plugins, Nitro - presets, and deployment targets for any platform. ---- - -The `defineConfig` helper is from `@solidjs/start/config` and is used within [`app.config.ts`](/solid-start/v1/reference/entrypoints/app-config). - -It takes a configuration object with settings for SolidStart, Vite, and Nitro. - -## Configuring Vite - -SolidStart supports most Vite options, including plugins via the `vite` option: - -```tsx -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - vite: { - // vite options - plugins: [], - }, -}); -``` - -The `vite` option can also be a function that can be customized for each Vinxi router. - -In SolidStart, 3 routers are used: - -- `server` - server-side routing -- `client` - for the client-side routing -- `server-function` - server functions. - -```tsx -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - vite({ router }) { - if (router === "server") { - } else if (router === "client") { - } else if (router === "server-function") { - } - return { plugins: [] }; - }, -}); -``` - -## Serialization - -SolidStart serializes server function payloads so they can move between server and client. You can configure the serializer mode to balance performance, payload size, and Content Security Policy (CSP) constraints. - -```tsx -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - serialization: { - mode: "json", - }, -}); -``` - -### Modes - -- `json`: Uses `JSON.parse` on the client. This is the safest option for strict CSP because it avoids `eval`. Payloads can be slightly larger. -- `js`: Uses Seroval's JS serializer for smaller payloads and better performance, but it relies on `eval` during client-side deserialization and requires `unsafe-eval` in CSP. - -### Defaults - -- SolidStart v1 defaults to `js` for backwards compatibility. -- SolidStart v2 defaults to `json` for CSP compatibility. - -### Supported types (default) - -SolidStart enables Seroval plus a default set of web platform plugins. These plugins add support for: - -- `AbortSignal`, `CustomEvent`, `DOMException`, `Event` -- `FormData`, `Headers`, `ReadableStream` -- `Request`, `Response` -- `URL`, `URLSearchParams` - -Seroval supports additional value types. The compatibility list is broader than what SolidStart enables by default, so treat it as a superset. See the full list in the [Seroval compatibility docs](https://github.com/lxsmnsyc/seroval/blob/main/docs/COMPATIBILITY.md). - -## Configuring Nitro - -SolidStart uses [Nitro](https://nitro.build/) to run on a number of platforms. -The `server` option exposes some Nitro options including the build and deployment presets. -An overview of all available presets is available in the [Deploy section of the Nitro documentation](https://nitro.build/deploy). - -Some common ones include: - -**Servers** - -- [Node.js Server](https://nitro.build/deploy/runtimes/node#handler-advanced) (`node`) (Default) -- [Deno Server](https://nitro.build/deploy/runtimes/deno) (`deno_server`) -- [Bun Server](https://nitro.build/deploy/runtimes/bun) (`bun`) - -**Providers** - -- [Netlify Functions and Edge](https://nitro.build/deploy/providers/netlify) (`netlify`, `netlify-edge`) -- [Vercel Functions and Edge](https://nitro.build/deploy/providers/vercel) (`vercel`, `vercel-edge`) -- [AWS Lambda and Lambda@Edge](https://nitro.build/deploy/providers/aws) (`aws_lambda`) -- [Cloudflare Workers and Pages](https://nitro.build/deploy/providers/cloudflare) (`cloudflare`, `cloudflare_pages`, `cloudflare_module`) -- [Deno Deploy](https://nitro.build/deploy/providers/deno-deploy) (`deno_deploy`) - -**Static site generation** - -- [Route pre-rendering](/solid-start/v1/building-your-application/route-prerendering) - -By passing no arguments, the default will be the Node preset. -Other presets may be automatically detected by the provider, however, if not, they must be added to the configuration within the `server-preset` option. - -For example, using Netlify Edge would look like the following: - -```tsx -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - preset: "netlify_edge", - }, -}); -``` - -#### Special note - -SolidStart uses async local storage. -Netlify, Vercel, and Deno support this out of the box but if you're using Cloudflare you will need to specify the following: - -```js -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({ - server: { - preset: "cloudflare_module", - rollupConfig: { - external: ["__STATIC_CONTENT_MANIFEST", "node:async_hooks"], - }, - }, -}); -``` - -Within `wrangler.toml` you will need to enable node compatibility: - -``` -compatibility_flags = [ "nodejs_compat" ] -``` - -## Parameters - -| Property | Type | Default | Description | -| -------------------- | ------------------------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ssr | boolean | true | Toggle between client and server rendering. | -| solid | object | | Configuration object for [vite-plugin-solid](https://github.com/solidjs/vite-plugin-solid) | -| extensions | string[] | ["js", "jsx", "ts", "tsx"] | Array of file extensions to be treated as routes. | -| server | object | | Nitro server config options | -| serialization | object | | Serialization settings for server function payloads. | -| appRoot | string | "./src" | The path to the root of the application. | -| routeDir | string | "./routes" | The path to where the routes are located. | -| middleware | string | | The path to an optional [middleware](/solid-start/v1/advanced/middleware) file. | -| devOverlay | boolean | true | Toggle the dev overlay. | -| experimental.islands | boolean | false | Enable "islands" mode. | -| vite | `ViteConfig` or `({ router })=>ViteConfig` | | [Vite config object](https://vitejs.dev/config/shared-options.html). Can be configured for each `router` which has the string value "server", "client" or "server-function"` | diff --git a/src/routes/solid-start/v1/reference/entrypoints/(0)app-config.mdx b/src/routes/solid-start/v1/reference/entrypoints/(0)app-config.mdx deleted file mode 100644 index 359652927..000000000 --- a/src/routes/solid-start/v1/reference/entrypoints/(0)app-config.mdx +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: app.config.ts -use_cases: >- - app config, solidstart config, vinxi config -tags: - - config - - entrypoint -version: "1.0" -description: >- - app.config.ts exports the app configuration. ---- - -`app.config.ts` is the app configuration entrypoint. - -## Import - -```tsx -import { defineConfig } from "@solidjs/start/config"; -``` - -## Type - -```tsx -export default defineConfig(baseConfig); -``` - -## Parameters - -`app.config.ts` passes its configuration object to [`defineConfig`](/solid-start/v1/reference/config/define-config). - -## Return value - -The default export is the value returned by [`defineConfig`](/solid-start/v1/reference/config/define-config). - -## Behavior - -- The config entry uses `@solidjs/start/config`. -- This file is read as the app configuration file. - -## Examples - -### Basic usage - -```tsx -import { defineConfig } from "@solidjs/start/config"; - -export default defineConfig({}); -``` - -## Related - -- [`defineConfig`](/solid-start/v1/reference/config/define-config) diff --git a/src/routes/solid-start/v1/reference/entrypoints/app.mdx b/src/routes/solid-start/v1/reference/entrypoints/app.mdx deleted file mode 100644 index c3a201c08..000000000 --- a/src/routes/solid-start/v1/reference/entrypoints/app.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: app.tsx -use_cases: >- - app root, routes, root component -tags: - - entrypoint - - app - - routes -version: "1.0" -description: >- - app.tsx is the app root module. ---- - -`app.tsx` is the resolved app root module. - -## Import - -`app.tsx` is loaded as the virtual app module. - -## Type - -```tsx -export default function App(): JSX.Element; -``` - -## Parameters - -The default app component takes no required arguments. - -## Return value - -- **Type:** `JSX.Element` - -Returns the root app element. - -## Behavior - -- The config aliases `#start/app` to the app module under `appRoot`. -- Default `appRoot` is `"./src"`. -- Entry files use `.jsx` when `${appRoot}/app.jsx` exists; otherwise they use `.tsx`. - -## Examples - -### Basic usage - -```tsx -import { Router } from "@solidjs/router"; -import { FileRoutes } from "@solidjs/start/router"; - -export default function App() { - return ( - - - - ); -} -``` - -## Related - -- [`FileRoutes`](/solid-start/v1/reference/routing/file-routes) diff --git a/src/routes/solid-start/v1/reference/entrypoints/entry-client.mdx b/src/routes/solid-start/v1/reference/entrypoints/entry-client.mdx deleted file mode 100644 index a1b01e868..000000000 --- a/src/routes/solid-start/v1/reference/entrypoints/entry-client.mdx +++ /dev/null @@ -1,55 +0,0 @@ ---- -title: entry-client.tsx -use_cases: >- - client entry, hydration entry, browser entry -tags: - - entrypoint - - client - - hydration -version: "1.0" -description: >- - entry-client.tsx mounts StartClient in the browser. ---- - -`entry-client.tsx` is the client entry module. - -## Import - -```tsx -import { mount, StartClient } from "@solidjs/start/client"; -``` - -## Type - -```tsx -mount(() => , element); -``` - -## Parameters - -`entry-client.tsx` passes a `StartClient` render function and DOM element to [`mount`](/solid-start/v1/reference/client/mount). - -## Return value - -The entry module does not need to export a value. - -## Behavior - -- `defineConfig` uses `${appRoot}/entry-client${entryExtension}` as the client handler. -- The default `appRoot` is `"./src"`. -- Entry extension is `.jsx` when `${appRoot}/app.jsx` exists; otherwise it is `.tsx`. - -## Examples - -### Basic usage - -```tsx -import { mount, StartClient } from "@solidjs/start/client"; - -mount(() => , document.getElementById("app")!); -``` - -## Related - -- [`mount`](/solid-start/v1/reference/client/mount) -- [`StartClient`](/solid-start/v1/reference/client/start-client) diff --git a/src/routes/solid-start/v1/reference/entrypoints/entry-server.mdx b/src/routes/solid-start/v1/reference/entrypoints/entry-server.mdx deleted file mode 100644 index 49eb607f7..000000000 --- a/src/routes/solid-start/v1/reference/entrypoints/entry-server.mdx +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: entry-server.tsx -use_cases: >- - server entry, request handler, document rendering -tags: - - entrypoint - - server - - rendering -version: "1.0" -description: >- - entry-server.tsx exports the server handler. ---- - -`entry-server.tsx` is the server entry module. - -## Import - -```tsx -import { createHandler, StartServer } from "@solidjs/start/server"; -``` - -## Type - -```tsx -export default createHandler((event) => ); -``` - -## Parameters - -The handler callback receives a `PageEvent`. - -## Return value - -The default export is the event handler returned by [`createHandler`](/solid-start/v1/reference/server/create-handler). - -## Behavior - -- `defineConfig` uses `${appRoot}/entry-server${entryExtension}` as the server handler. -- The default `appRoot` is `"./src"`. -- Entry extension is `.jsx` when `${appRoot}/app.jsx` exists; otherwise it is `.tsx`. -- For setting different SSR modes (sync | async | stream), see [`createHandler`](/solid-start/v1/reference/server/create-handler). - -## Examples - -### Basic usage - -```tsx -import { createHandler, StartServer } from "@solidjs/start/server"; - -function Document(props) { - return ( - - {props.assets} - -
{props.children}
- {props.scripts} - - - ); -} - -export default createHandler((event) => ); -``` - -## Related - -- [`createHandler`](/solid-start/v1/reference/server/create-handler) -- [`StartServer`](/solid-start/v1/reference/server/start-server) diff --git a/src/routes/solid-start/v1/reference/routing/file-routes.mdx b/src/routes/solid-start/v1/reference/routing/file-routes.mdx deleted file mode 100644 index 25b155f30..000000000 --- a/src/routes/solid-start/v1/reference/routing/file-routes.mdx +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: FileRoutes -use_cases: >- - file routes, route definitions, filesystem routes -tags: - - routing - - files - - routes - - component -version: "1.0" -description: >- - FileRoutes returns route definitions generated from filesystem routes. ---- - -`FileRoutes` is a component-like function that returns route definitions generated from filesystem routes. - -## Import - -```tsx -import { FileRoutes } from "@solidjs/start/router"; -``` - -## Type - -```tsx -const FileRoutes: () => any[]; -``` - -## Parameters - -`FileRoutes` takes no arguments. - -## Return value - -- **Type:** `any[]` - -Returns generated route definitions. - -## Behavior - -- On the server, `FileRoutes` returns `getRequestEvent().routes`. -- Client routes are created from the generated page route config and cached in module scope. -- Generated route info includes `filesystem: true`. - -## Examples - -### Basic usage - -```tsx -import { Router } from "@solidjs/router"; -import { FileRoutes } from "@solidjs/start/router"; - -export default function App() { - return ( - - - - ); -} -``` diff --git a/src/routes/solid-start/v1/reference/server/create-handler.mdx b/src/routes/solid-start/v1/reference/server/create-handler.mdx deleted file mode 100644 index 33bc0c85e..000000000 --- a/src/routes/solid-start/v1/reference/server/create-handler.mdx +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: createHandler -use_cases: >- - server entry, request handler, rendering mode -tags: - - server - - handler - - rendering -version: "1.0" -description: >- - createHandler creates the server handler. ---- - -`createHandler` creates the handler used by the server entry. - -## Import - -```tsx -import { createHandler } from "@solidjs/start/server"; -``` - -## Type - -```tsx -type HandlerOptions = { - mode?: "sync" | "async" | "stream"; - nonce?: string; - renderId?: string; - onCompleteAll?: (options: { write: (value: any) => void }) => void; - onCompleteShell?: (options: { write: (value: any) => void }) => void; -}; - -function createHandler( - fn: (context: PageEvent) => unknown, - options?: - | HandlerOptions - | ((context: PageEvent) => HandlerOptions | Promise), - routerLoad?: (event: FetchEvent) => Promise -): EventHandler>; -``` - -## Parameters - -### `fn` - -- **Type:** `(context: PageEvent) => unknown` -- **Required:** Yes - -Function that returns the server-rendered document. - -### `options` - -- **Type:** `HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise)` -- **Default:** `{}` -- **Required:** No - -Rendering options or a function that returns rendering options. -The supported options are: - -The `options` object supports these fields: - -| Name | Type | Required | Default | Description | -| ----------------- | ---------------------------------------------------- | -------- | ---------- | ----------------------------------------------- | -| `mode` | `"sync" \| "async" \| "stream"` | No | `"stream"` | Rendering mode. | -| `nonce` | `string` | No | None | Nonce assigned to the page event. | -| `renderId` | `string` | No | None | Render identifier passed to the render context. | -| `onCompleteAll` | `(options: { write: (value: any) => void }) => void` | No | None | Callback used when all stream content is ready. | -| `onCompleteShell` | `(options: { write: (value: any) => void }) => void` | No | None | Callback used when the shell stream is ready. | - -### `routerLoad` - -- **Type:** `(event: FetchEvent) => Promise` -- **Required:** No - -Function called with the fetch event before API route matching and page rendering. - -## Return value - -- **Type:** `EventHandler>` - -Returns a Vinxi event handler. - -## Behavior - -- Calls `createBaseHandler(fn, createPageEvent, options, routerLoad)`. -- When `routerLoad` is provided, it runs before API route matching and page rendering. -- Matching API routes run before page rendering. For `HEAD` requests, the route `HEAD` export is used, with fallback to `GET`. -- Synchronous mode and disabled SSR render with `renderToString` and return the HTML string. -- Async mode returns the `renderToStream` result. -- Stream mode is the default and returns a readable stream. -- If page rendering sets a `Location` response header, the handler sends or writes a redirect response depending on the render phase. - -## Examples - -### Basic usage - -```tsx -import { createHandler, StartServer } from "@solidjs/start/server"; - -export default createHandler((event) => ); -``` - -## Related - -- [`StartServer`](/solid-start/v1/reference/server/start-server) diff --git a/src/routes/solid-start/v1/reference/server/create-middleware.mdx b/src/routes/solid-start/v1/reference/server/create-middleware.mdx deleted file mode 100644 index 5909e02c0..000000000 --- a/src/routes/solid-start/v1/reference/server/create-middleware.mdx +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: createMiddleware -use_cases: >- - request middleware, response middleware, h3 middleware -tags: - - server - - middleware - - request - - response -version: "1.0" -description: >- - createMiddleware creates middleware definitions. ---- - -`createMiddleware` wraps request and response middleware functions with fetch events. - -## Import - -```tsx -import { createMiddleware } from "@solidjs/start/middleware"; -``` - -## Type - -```tsx -type RequestMiddleware = ( - event: FetchEvent -) => Response | Promise | void | Promise; - -type ResponseMiddleware = ( - event: FetchEvent, - response: { body?: unknown } -) => Response | Promise | void | Promise; - -function createMiddleware(args: { - onRequest?: RequestMiddleware | RequestMiddleware[]; - onBeforeResponse?: ResponseMiddleware | ResponseMiddleware[]; -}): { - onRequest?: _RequestMiddleware | _RequestMiddleware[]; - onBeforeResponse?: _ResponseMiddleware | _ResponseMiddleware[]; -}; -``` - -## Parameters - -### `args` - -- **Type:** `{ onRequest?: RequestMiddleware | RequestMiddleware[]; onBeforeResponse?: ResponseMiddleware | ResponseMiddleware[] }` -- **Required:** Yes - -Middleware functions grouped by request phase. - -## Return value - -- **Type:** `{ onRequest?: _RequestMiddleware | _RequestMiddleware[]; onBeforeResponse?: _ResponseMiddleware | _ResponseMiddleware[] }` - -Returns the value from Vinxi `defineMiddleware`. - -## Behavior - -- `onRequest` functions are wrapped so that a returned response ends the middleware. -- `onBeforeResponse` functions are wrapped with the current fetch event and response object. -- Single middleware inputs produce single wrapped functions. -- Array inputs are mapped to arrays of wrapped functions. - -## Examples - -### Basic usage - -```tsx -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware({ - onRequest: async (event) => { - event.response.headers.set( - "x-request-path", - new URL(event.request.url).pathname - ); - }, -}); -``` diff --git a/src/routes/solid-start/v1/reference/server/get-server-function-meta.mdx b/src/routes/solid-start/v1/reference/server/get-server-function-meta.mdx deleted file mode 100644 index a1949b5a1..000000000 --- a/src/routes/solid-start/v1/reference/server/get-server-function-meta.mdx +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: getServerFunctionMeta -use_cases: >- - server function metadata, request metadata, server functions -tags: - - server - - functions - - metadata -version: "1.0" -description: >- - getServerFunctionMeta returns metadata for the current server function request. ---- - -`getServerFunctionMeta` reads server function metadata from the current request event locals. - -## Import - -```tsx -import { getServerFunctionMeta } from "@solidjs/start"; -``` - -## Type - -```tsx -interface ServerFunctionMeta { - id: string; -} - -function getServerFunctionMeta(): ServerFunctionMeta | undefined; -``` - -## Parameters - -`getServerFunctionMeta` takes no arguments. - -## Return value - -- **Type:** `ServerFunctionMeta | undefined` - -Returns `getRequestEvent()?.locals.serverFunctionMeta`. - -## Behavior - -- When there is no request event, `getServerFunctionMeta` returns `undefined`. - -## Examples - -### Basic usage - -```tsx -import { getServerFunctionMeta } from "@solidjs/start"; - -const meta = getServerFunctionMeta(); -``` diff --git a/src/routes/solid-start/v1/reference/server/get.mdx b/src/routes/solid-start/v1/reference/server/get.mdx deleted file mode 100644 index 29e4b2f8f..000000000 --- a/src/routes/solid-start/v1/reference/server/get.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: GET -use_cases: >- - server functions, get handlers, query functions -tags: - - server - - get - - function -version: "1.0" -description: >- - GET returns the GET handler attached to a server function. ---- - -`GET` returns the `.GET` property from a function. - -## Import - -```tsx -import { GET } from "@solidjs/start"; -``` - -## Type - -```tsx -function GET any>( - fn: T -): (...args: Parameters) => ReturnType; -``` - -## Parameters - -### `fn` - -- **Type:** `T extends (...args: any[]) => any` -- **Required:** Yes - -Function with a `GET` property. - -## Return value - -- **Type:** `(...args: Parameters) => ReturnType` - -Returns `fn.GET`. - -## Examples - -### Basic usage - -```tsx -import { GET } from "@solidjs/start"; - -const getMessage = Object.assign(async () => "hello", { - GET: async () => "hello", -}); - -const handler = GET(getMessage); -``` diff --git a/src/routes/solid-start/v1/reference/server/http-header.mdx b/src/routes/solid-start/v1/reference/server/http-header.mdx deleted file mode 100644 index 8eddf5109..000000000 --- a/src/routes/solid-start/v1/reference/server/http-header.mdx +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: HttpHeader -use_cases: >- - response headers, server rendering, header cleanup -tags: - - server - - headers - - component -version: "1.0" -description: >- - HttpHeader sets or appends a response header during server rendering. ---- - -`HttpHeader` is a component that sets or appends a response header on the server. - -## Import - -```tsx -import { HttpHeader } from "@solidjs/start"; -``` - -## Type - -```tsx -interface HttpHeaderProps { - name: string; - value: string; - append?: boolean; -} - -const HttpHeader: (props: HttpHeaderProps) => null; -``` - -## Props - -### `name` - -- **Type:** `string` -- **Optional:** No - -Header name. - -### `value` - -- **Type:** `string` -- **Optional:** No - -Header value. - -### `append` - -- **Type:** `boolean` -- **Optional:** Yes - -Controls whether the value is appended instead of set. - -## Behavior - -- On the server, the current request event is read. -- Truthy `append` calls `event.response.headers.append(name, value)`, while falsy `append` calls `event.response.headers.set(name, value)`. -- During cleanup, its own header value is removed unless the event has already completed or been handled. -- Client rendering returns `null`. - -## Examples - -### Basic usage - -```tsx -import { HttpHeader } from "@solidjs/start"; - -export default function Page() { - return ; -} -``` diff --git a/src/routes/solid-start/v1/reference/server/http-status-code.mdx b/src/routes/solid-start/v1/reference/server/http-status-code.mdx deleted file mode 100644 index 92e0c34e9..000000000 --- a/src/routes/solid-start/v1/reference/server/http-status-code.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: HttpStatusCode -use_cases: >- - response status, server rendering, status text -tags: - - server - - status - - component -version: "1.0" -description: >- - HttpStatusCode sets the response status during server rendering. ---- - -`HttpStatusCode` is a component that sets the response status code on the server. - -## Import - -```tsx -import { HttpStatusCode } from "@solidjs/start"; -``` - -## Type - -```tsx -interface HttpStatusCodeProps { - code: number; - text?: string; -} - -const HttpStatusCode: (props: HttpStatusCodeProps) => null; -``` - -## Props - -### `code` - -- **Type:** `number` -- **Optional:** No - -HTTP status code assigned to the response. - -### `text` - -- **Type:** `string` -- **Optional:** Yes - -HTTP status text assigned to the response. - -## Behavior - -- On the server, `event.response.status` is set to `code`. -- `event.response.statusText` is set to `text`. -- During cleanup, the response status resets to `200` when the event is not complete and the native event has not been handled. -- Client rendering returns `null`. - -## Examples - -### Basic usage - -```tsx -import { HttpStatusCode } from "@solidjs/start"; - -export default function NotFound() { - return ; -} -``` diff --git a/src/routes/solid-start/v1/reference/server/start-server.mdx b/src/routes/solid-start/v1/reference/server/start-server.mdx deleted file mode 100644 index cda3b87a1..000000000 --- a/src/routes/solid-start/v1/reference/server/start-server.mdx +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: StartServer -use_cases: >- - server entry, document rendering, html shell -tags: - - server - - rendering - - component -version: "1.0" -description: >- - StartServer renders the app inside a document component. ---- - -`StartServer` is a component that renders the generated app inside the provided document component. - -## Import - -```tsx -import { StartServer } from "@solidjs/start/server"; -``` - -## Type - -```tsx -type DocumentComponentProps = { - assets: JSX.Element; - scripts: JSX.Element; - children?: JSX.Element; -}; - -function StartServer(props: { - document: Component; -}): JSX.Element; -``` - -## Props - -### `document` - -- **Type:** `Component` -- **Optional:** No - -Document component rendered around the app. - -## Behavior - -- Reads the current request event as a `PageEvent`. -- Registers page assets with `useAssets`. -- Renders `` before the document component. -- Passes `assets`, `scripts`, and `children` to the document component. -- Wraps the app with error boundaries. - -## Examples - -### Basic usage - -```tsx -import { createHandler, StartServer } from "@solidjs/start/server"; - -function Document(props) { - return ( - - {props.assets} - -
{props.children}
- {props.scripts} - - - ); -} - -export default createHandler((event) => ); -``` - -## Related - -- [`createHandler`](/solid-start/v1/reference/server/create-handler) diff --git a/src/routes/solid-start/v1/reference/server/use-server.mdx b/src/routes/solid-start/v1/reference/server/use-server.mdx deleted file mode 100644 index e128ec4cf..000000000 --- a/src/routes/solid-start/v1/reference/server/use-server.mdx +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: '"use server"' -use_cases: >- - server functions, server-only functions, server references -tags: - - server - - directive - - functions -version: "1.0" -description: >- - "use server" marks server functions for the server function compiler. ---- - -`"use server"` is the directive string recognized by the server functions compiler. - -## Import - -No import is required for the directive. - -## Type - -```tsx -const DIRECTIVE = "use server"; -``` - -## Parameters - -The directive has no parameters. - -## Return value - -The directive does not return a value. - -## Behavior - -- The compiler uses `"use server"` as its directive string. -- In client builds, transformed server references use the configured client runtime. -- SSR and server-function builds use the configured server runtime for transformed server references. -- Valid transformed modules are added to the server function manifest. - -## Examples - -### Function directive - -```tsx -const logMessage = async (message: string) => { - "use server"; - console.log(message); -}; -``` - -### File directive - -```tsx -"use server"; - -export async function logMessage(message: string) { - console.log(message); -} -``` - -## Related - -- [`getServerFunctionMeta`](/solid-start/v1/reference/server/get-server-function-meta) diff --git a/src/routes/solid-start/v2/(0)building-your-application/(0)routing.mdx b/src/routes/solid-start/v2/(0)building-your-application/(0)routing.mdx deleted file mode 100644 index 599028ac2..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(0)routing.mdx +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Routing -use_cases: >- - page navigation, url structure, dynamic paths, route organization, - filesystem routing, api endpoints -tags: - - routing - - filesystem - - pages - - dynamic - - api -version: "2.0" -description: >- - SolidStart v2 routing uses the filesystem router to map files in - src/routes to UI routes and API routes. ---- - -Routes come from the filesystem. -`FileRoutes` from `@solidjs/start/router` maps files in `src/routes` into route paths. - -This page covers the route filename conventions. - -## UI routes and API routes - -There are two route shapes: - -- Files with a default export become UI routes. -- Files that export HTTP method names such as `GET` or `POST` become API routes. - -You can read more about handler exports in [API routes](/solid-start/v2/building-your-application/api-routes). - -## Basic filename mapping - -File names map to paths using these rules: - -- `src/routes/index.tsx` becomes `/` -- `src/routes/about.tsx` becomes `/about` -- `src/routes/blog/index.tsx` becomes `/blog` -- `src/routes/blog/post.tsx` becomes `/blog/post` - -An `.mdx` file in `src/routes` is also treated as a page route. - -## Dynamic segments - -Bracketed segments become route params: - -- `src/routes/users/[id].tsx` becomes `/users/:id` -- `src/routes/users/[[id]].tsx` becomes `/users/:id?` -- `src/routes/docs/[...slug].tsx` becomes `/docs/*slug` - -Read them with [`useParams`](/solid-router/reference/primitives/use-params): - -```tsx title="src/routes/users/[id].tsx" -import { useParams } from "@solidjs/router"; - -export default function UserPage() { - const params = useParams(); - return

User {params.id}

; -} -``` - -## Route config exports - -The filesystem router also looks for an exported `route` object alongside a page component. -That lets a route file attach route-level behavior while still default-exporting UI. - -```tsx title="src/routes/posts/[id].tsx" -import { query, createAsync, type RouteDefinition } from "@solidjs/router"; - -const getPost = query(async (id: string) => { - "use server"; - const response = await fetch(`https://example.com/api/posts/${id}`); - return response.json(); -}, "post"); - -export const route = { - preload: ({ params }) => getPost(params.id), -} satisfies RouteDefinition; - -export default function PostPage(props: { params: { id: string } }) { - const post = createAsync(() => getPost(props.params.id)); - return
{JSON.stringify(post(), null, 2)}
; -} -``` diff --git a/src/routes/solid-start/v2/(0)building-your-application/(1)api-routes.mdx b/src/routes/solid-start/v2/(0)building-your-application/(1)api-routes.mdx deleted file mode 100644 index 2ebff1583..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(1)api-routes.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: API routes -use_cases: >- - rest api, webhooks, oauth callbacks, server endpoints, route handlers, - request handling -tags: - - api - - http - - server - - handlers - - endpoints -version: "2.0" -description: >- - SolidStart v2 API routes are filesystem routes that export HTTP method - handlers and receive typed APIEvent objects from @solidjs/start/server. ---- - -Use an API route when you need a route that returns data or handles incoming HTTP requests instead of rendering page UI. - -A file becomes an API route when it exports one or more HTTP method names such as [`GET`](/solid-start/v2/reference/server/get), `POST`, `PATCH`, or `DELETE`. - -## Create an API route - -An API route lives in `src/routes` and exports handler functions named after the HTTP methods it handles. - -```tsx title="src/routes/api/ping.ts" -export function GET() { - return new Response("pong"); -} -``` - -The package exports `APIEvent` from `@solidjs/start/server`. -That type includes: - -- `request` for the incoming `Request` -- `params` for dynamic path parameters -- `response` for the mutable response stub -- `locals` for request-scoped locals -- `nativeEvent` for the underlying H3 event - -```tsx title="src/routes/api/users/[id].ts" -import type { APIEvent } from "@solidjs/start/server"; - -export async function GET({ params }: APIEvent) { - return Response.json({ userId: params.id }); -} -``` - -## File naming follows the same router - -API routes use the same path conventions as UI routes. -For example: - -- `src/routes/api/users.ts` becomes `/api/users` -- `src/routes/api/users/[id].ts` becomes `/api/users/:id` -- `src/routes/api/files/[...slug].ts` becomes `/api/files/*slug` - -## HEAD fallback - -If a route exports `GET` but not `HEAD`, `HEAD` requests are handled by the `GET` handler. -Export `HEAD` explicitly when you need custom behavior. - -## Request helpers - -Cookie, session, header, and request helpers are exported from `@solidjs/start/http`. - -```tsx title="src/routes/api/session.ts" -import { getCookie } from "@solidjs/start/http"; -import type { APIEvent } from "@solidjs/start/server"; - -export function GET(_event: APIEvent) { - const userId = getCookie("userId"); - if (!userId) { - return new Response("Not logged in", { status: 401 }); - } - - return Response.json({ userId }); -} -``` - -## When to use an API route - -API routes are a good fit when you need: - -- endpoints for other clients -- webhook receivers -- auth callback handlers -- routes that return non-HTML responses - -If the data is only needed by your route UI, prefer [Data fetching](/solid-start/v2/building-your-application/data-fetching) or [Data mutation](/solid-start/v2/building-your-application/data-mutation) before introducing a separate API boundary. diff --git a/src/routes/solid-start/v2/(0)building-your-application/(2)css-and-styling.mdx b/src/routes/solid-start/v2/(0)building-your-application/(2)css-and-styling.mdx deleted file mode 100644 index 6afe086de..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(2)css-and-styling.mdx +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: CSS and styling -use_cases: >- - styling components, css modules, scoped styles, component styling, design - system setup, visual customization -tags: - - css - - styling - - modules - - components - - design - - vite -version: "2.0" -description: >- - Style your SolidStart components with CSS, CSS modules, and other styling - solutions. Implement scoped styles and design systems. ---- - -SolidStart v2 introduces a completely revamped CSS rendering mechanism: - -- CSS deduplication during server-side rendering works more consistently across the board. -- Hot module replacement (HMR) of route CSS is now directly managed by Vite instead of SolidStart. -- CSS in `lazy`-loaded components is now properly server-side rendered and does not result in flashes of unstyled content. -- Client-side navigation now mounts new CSS directly via Vite instead of SolidStart. - - Server HTML responses no longer have to include the whole assets manifest. -- Client-side navigation no longer unmounts old CSS, more closely following Vite's native behaviour. - -## Styling components - -You can import CSS using ESM syntax anywhere within the component tree. Styles imported as such, are globally mounted in your app. - -```tsx title="Card.tsx" tab="component" -import "./Card.css"; - -const Card = (props) => { - return ( -
-

{props.title}

-

{props.text}

-
- ); -}; -``` - -```css title="Card.css" tab="component" -.card { - background-color: #446b9e; -} - -h1 { - font-size: 1.5em; - font-weight: bold; -} - -p { - font-size: 1em; - font-weight: normal; -} -``` - -## Locally scoped styles - -SolidStart supports [CSS modules](https://github.com/css-modules/css-modules), allowing you to locally scope the imported CSS. - -As is standard with [Vite](https://vitejs.dev/guide/features.html#css-modules), any file ending with `.module.css`, `.module.scss` or `.module.sass` is considered a CSS module. Reference the generated css class names via the imported object, e.g. `styles.card`. - -```tsx title="Card.tsx" tab="component" -import styles from "./Card.module.css"; - -const Card = (props) => { - return ( -
-

{props.title}

-

{props.text}

-
- ); -}; -``` - -```css title="Card.module.css" tab="component" -.card { - background-color: #446b9e; -} - -div.card > h1 { - font-size: 1.5em; - font-weight: bold; -} - -div.card > p { - font-size: 1em; - font-weight: normal; -} -``` - -## Route-specific global styles - -Imported CSS stays in the document when navigating to different routes. Therefore routes with different global styles will overlap each other. There exist several strategies to get around this limitation: - -### Apply \:has pseudo-class - -If you only have to apply few global CSS rules for one specific route, you can use the CSS [\:has](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:has) pseudo-class, to tie the global CSS to the route: - -```tsx title="routes/about.tsx" tab="component" -import "./about.css"; - -export default function About() { - return ( -
-

About us

-
- ); -} -``` - -```css title="routes/about.css" tab="component" -body:has(main[data-route="about"]) { - background-color: #446b9e; - color: white; -} -``` - -### Import with ?url - -If the route depends on complex global CSS (e.g. using Tailwind only in one specific route), optimizing all selectors with `:has` might not always be possible. Instead you can import the CSS file by URL and mount it through JSX: - -```tsx title="routes/about.tsx" tab="component" -import { Link } from "@solidjs/meta"; -import styleUrl from "./about.css?url"; - -export default function About() { - return ( -
- -

About us

-
- ); -} -``` - -```css title="routes/about.css" tab="component" -@import "tailwindcss"; -``` - -## Lazy loading - -[Lazy](https://docs.solidjs.com/reference/component-apis/lazy) loading components with CSS is now fully supported in SolidStart v2 and no longer results in flashes of unstyled content (FOUC): - -```tsx title="App.tsx" tab="component" -import { lazy } from "solid-js"; - -// Lazy with dynamic import -const Card = lazy(() => import("./Card.tsx")); - -// Lazy with glob import -const components = import.meta.glob("./Car*.tsx"); -const Card2 = lazy(Object.values(components)[0]); - -const App = (props) => { - return ( -
- - -
- ); -}; -``` - -```tsx title="Card.tsx" tab="component" -import "./Card.css"; - -const Card = (props) => { - return ( -
-

{props.title}

-

{props.text}

-
- ); -}; -``` - -```css title="Card.css" tab="component" -.card { - background-color: #446b9e; -} - -h1 { - font-size: 1.5em; - font-weight: bold; -} - -p { - font-size: 1em; - font-weight: normal; -} -``` - -## Other ways to style components - -SolidStart is built on top of Solid, meaning styling is not limited to CSS. -To see other ways to style components, see the [styling section in the Solid documentation](/guides/styling-your-components). diff --git a/src/routes/solid-start/v2/(0)building-your-application/(3)data-fetching.mdx b/src/routes/solid-start/v2/(0)building-your-application/(3)data-fetching.mdx deleted file mode 100644 index 1da23b5f5..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(3)data-fetching.mdx +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: Data fetching -use_cases: >- - api calls, database queries, loading states, preloading data, server-side - fetching, route data -tags: - - fetch - - data - - query - - async - - server -version: "2.0" -description: >- - Fetch data in SolidStart v2 with Solid Router queries, createAsync, and - server-backed functions compiled from the use server directive. ---- - -Data loading is built around Solid Router's [`query`](/solid-router/reference/data-apis/query) API and [`createAsync`](/solid-router/reference/data-apis/create-async). -The `"use server"` directive lets a query body run only on the server when needed. - -## Basic query usage - -Use `query` to define cached data loading and `createAsync` to read the result inside a route component. - -```tsx title="src/routes/posts.tsx" -import { For } from "solid-js"; -import { createAsync, query } from "@solidjs/router"; - -const getPosts = query(async () => { - const response = await fetch("https://example.com/api/posts"); - return response.json() as Promise>; -}, "posts"); - -export default function PostsPage() { - const posts = createAsync(() => getPosts()); - - return {(post) =>
  • {post.title}
  • }
    ; -} -``` - -## Keep the data function on the server - -If your query needs direct access to server-only resources, add the `"use server"` directive inside the query function. - -```tsx title="src/routes/account.tsx" -import { createAsync, query } from "@solidjs/router"; -import { useSession } from "@solidjs/start/http"; - -const getCurrentUser = query(async () => { - "use server"; - - const session = await useSession<{ userId?: string }>({ - password: process.env.SESSION_SECRET as string, - name: "session", - }); - - return { userId: session.data.userId ?? null }; -}, "currentUser"); - -export default function AccountPage() { - const user = createAsync(() => getCurrentUser()); - return
    {JSON.stringify(user(), null, 2)}
    ; -} -``` - -## Preload route data - -If you want to warm the query before rendering the page, export a `route.preload` function from the route module. - -```tsx title="src/routes/posts/[id].tsx" -import { createAsync, query, type RouteDefinition } from "@solidjs/router"; - -const getPost = query(async (id: string) => { - "use server"; - const response = await fetch(`https://example.com/api/posts/${id}`); - return response.json(); -}, "post"); - -export const route = { - preload: ({ params }) => getPost(params.id), -} satisfies RouteDefinition; - -export default function PostPage(props: { params: { id: string } }) { - const post = createAsync(() => getPost(props.params.id)); - return
    {JSON.stringify(post(), null, 2)}
    ; -} -``` - -Cache invalidation and advanced query behavior are handled by [Solid Router](/solid-router), so use the Solid Router references when you need lower-level cache semantics. diff --git a/src/routes/solid-start/v2/(0)building-your-application/(4)data-mutation.mdx b/src/routes/solid-start/v2/(0)building-your-application/(4)data-mutation.mdx deleted file mode 100644 index 84320b069..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(4)data-mutation.mdx +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Data mutation -use_cases: >- - form submission, server writes, data updates, user input handling, - validation, actions -tags: - - forms - - actions - - mutations - - server - - validation -version: "2.0" -description: >- - Mutate data in SolidStart v2 with Solid Router actions and server-only action - bodies compiled from the use server directive. ---- - -Mutations run through Solid Router's [`action`](/solid-router/reference/data-apis/action) API. -When a mutation must run on the server, place the [`"use server"`](/solid-start/v2/reference/server/use-server) directive inside the action body. - -## Handle form submissions with actions - -An action can be passed directly to a form element, with named actions and form-driven submission tracking. - -```tsx title="src/routes/posts/new.tsx" -import { action } from "@solidjs/router"; - -const createPost = action(async (formData: FormData) => { - "use server"; - - const title = formData.get("title")?.toString() ?? ""; - return { created: title.length > 0, title }; -}, "createPost"); - -export default function NewPostPage() { - return ( -
    - - -
    - ); -} -``` - -## Show pending and error state - -Use [`useSubmission`](/solid-router/reference/data-apis/use-submission) from `@solidjs/router` to observe the active submission. - -```tsx title="src/routes/profile.tsx" -import { Show } from "solid-js"; -import { action, useSubmission } from "@solidjs/router"; - -const saveProfile = action(async (formData: FormData) => { - "use server"; - - const displayName = formData.get("displayName")?.toString(); - if (!displayName) { - throw new Error("Display name is required."); - } - - return { ok: true }; -}, "saveProfile"); - -export default function ProfilePage() { - const submission = useSubmission(saveProfile); - - return ( -
    - -

    {submission.error?.message}

    -
    - - -
    - ); -} -``` - -## Prefill action arguments - -Use `.with(...)` to prefill leading arguments. - -```tsx title="src/routes/projects/[id].tsx" -import { action } from "@solidjs/router"; - -const archiveProject = action(async (projectId: string, formData: FormData) => { - "use server"; - - return { - projectId, - reason: formData.get("reason")?.toString() ?? null, - }; -}, "archiveProject"); - -export default function ProjectPage(props: { params: { id: string } }) { - return ( -
    - - -
    - ); -} -``` - -## Pair actions with route data - -When a mutation changes data that is also loaded by a route `query`, keep the read path and write path close together. -That makes it easier to reason about revalidation behavior through the Solid Router data APIs. - -Read this page together with [Data fetching](/solid-start/v2/building-your-application/data-fetching). diff --git a/src/routes/solid-start/v2/(0)building-your-application/(5)head-and-metadata.mdx b/src/routes/solid-start/v2/(0)building-your-application/(5)head-and-metadata.mdx deleted file mode 100644 index ad2c5d156..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(5)head-and-metadata.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: Head and metadata -use_cases: >- - seo optimization, page titles, meta tags, og tags, social sharing, search - engine visibility, dynamic metadata -tags: - - seo - - metadata - - head - - title - - meta - - og-tags -version: "2.0" -description: >- - Manage SEO and metadata in SolidStart with dynamic titles, meta tags, and Open - Graph tags. ---- - -SolidStart does not bundle a metadata API. Use [`@solidjs/meta`](/solid-meta) to manage document titles, metadata, links, styles, and other elements in ``. - -```package-install -@solidjs/meta -``` - -## Add the provider - -Place `MetaProvider` in the router root so route metadata is collected during server rendering and updated during client navigation. - -```tsx title="src/app.tsx" {8,12} -import { MetaProvider } from "@solidjs/meta"; -import { Router } from "@solidjs/router"; -import { FileRoutes } from "@solidjs/start/router"; -import { Suspense } from "solid-js"; - -export default function App() { - return ( - ( - - {props.children} - - )} - > - - - ); -} -``` - -## Set route metadata - -Metadata components can be rendered from any route below `MetaProvider`. They are removed or updated when the route changes. - -```tsx title="src/routes/about.tsx" -import { Meta, Title } from "@solidjs/meta"; - -export default function About() { - return ( - <> - About | My site - - -

    About

    - - ); -} -``` - -## Use asynchronous data - -Metadata can read the same query result as the route. Wrap the rendered data in `Suspense` or `Show` when it may not be available immediately. - -```tsx title="src/routes/users/[id].tsx" -import { Title } from "@solidjs/meta"; -import { createAsync, query, type RouteSectionProps } from "@solidjs/router"; -import { Show } from "solid-js"; - -const getUser = query(async (id: string) => { - "use server"; - return { id, name: `User ${id}` }; -}, "user"); - -export default function User(props: RouteSectionProps) { - const user = createAsync(() => getUser(props.params.id)); - - return ( - - {(value) => ( - <> - {value().name} -

    {value().name}

    - - )} -
    - ); -} -``` - -See the [`@solidjs/meta` documentation](/solid-meta) for all supported head elements and provider behavior. diff --git a/src/routes/solid-start/v2/(0)building-your-application/(6)route-prerendering.mdx b/src/routes/solid-start/v2/(0)building-your-application/(6)route-prerendering.mdx deleted file mode 100644 index 1d4c3e00f..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(6)route-prerendering.mdx +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: Route pre-rendering -use_cases: >- - static site generation, ssg, blog sites, documentation, marketing pages, - performance optimization, seo improvement -tags: - - prerender - - ssg - - static - - performance - - build - - seo -version: "2.0" -description: >- - Pre-render SolidStart routes to static HTML with Nitro v3. ---- - -Route pre-rendering produces static HTML during `vite build`. Nitro writes the generated files to `.output/public`, where a CDN or server can serve them without rendering the route on each request. - -Configure prerendering through Nitro's top-level Vite configuration. - -## Pre-render selected routes - -```tsx title="vite.config.ts" -import { nitro } from "nitro/vite"; -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [solidStart(), nitro()], - nitro: { - prerender: { - routes: ["/", "/about"], - }, - }, -}); -``` - -## Crawl links - -Set `crawlLinks` to start at `/` and follow links found in rendered HTML. Add `routes` when the crawler needs additional entry points. - -```tsx title="vite.config.ts" -export default defineConfig({ - plugins: [solidStart(), nitro()], - nitro: { - prerender: { - crawlLinks: true, - failOnError: true, - }, - }, -}); -``` - -Dynamic routes that are not linked from a crawled page must be listed explicitly or discovered from another entry route. - -For retry, concurrency, ignore, and output-path options, see [Nitro's prerender configuration](https://nitro.build/config#prerender). diff --git a/src/routes/solid-start/v2/(0)building-your-application/(7)static-assets.mdx b/src/routes/solid-start/v2/(0)building-your-application/(7)static-assets.mdx deleted file mode 100644 index 0f4fa1290..000000000 --- a/src/routes/solid-start/v2/(0)building-your-application/(7)static-assets.mdx +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Static assets -use_cases: >- - images, fonts, documents, favicon, robots.txt, service workers, media files, - public resources -tags: - - assets - - images - - public - - static - - media - - files -version: "2.0" -description: >- - Manage static assets in SolidStart using the public directory or imports. - Serve images, fonts, documents, and media files. ---- - -Within SolidStart there are two ways to import static assets into your project: using the public directory and using imports. - -## Public directory - -Rich web applications use assets to create visuals. -In SolidStart, the `/public` directory can be used to store static assets. -These assets are served at the exact path they are in, relative to the public directory: - -``` -|-- public -| favicon.ico -> /favicon.ico -| |-- images -| | |-- logo.png -> /images/logo.png -| | |-- background.png -> /images/background.png -| |-- models -| | |-- player.gltf -> /models/player.gltf -| |-- documents -| | |-- report.pdf -> /documents/report.pdf -``` - -If you would like to reference an asset in the public directory, you can use the absolute path to the asset: - -```tsx { 5 } -export default function About() { - return ( - <> -

    About

    - Solid logo - - ); -} -``` - -This is ideal when you want to have human-readable, stable references to static assets. -This can be useful for assets such as: - -- documents -- service workers -- images, audio, and video -- manifest files -- metadata files (e.g., `robots.txt`, sitemaps) -- favicon - -## Importing assets - -Vite provides a way to import assets directly into your Solid components: - -```tsx -import logo from "./solid.png"; - -export default function About() { - return ( - <> -

    About

    - Solid logo - // Renders - Solid logo - - ); -} -``` - -When you use imports, Vite will create a hashed filename. -For example, `solid.png` will become `solid.2d8efhg.png`. - -## Public directory versus imports - -The public directory and imports are both valid ways to include static assets in your project. -The driver to use one over the other is based on your use case. - -For dynamic updates to your assets, using the public directory is the best choice. -It allows you to maintain full control over the asset URL paths, ensuring that the links remain consistent even when the assets are updated. - -When using imports, the filename is hashed and therefore will not be predictable over time. -This can be beneficial for cache busting but detrimental if you want to send someone a link to the asset. diff --git a/src/routes/solid-start/v2/(0)index.mdx b/src/routes/solid-start/v2/(0)index.mdx deleted file mode 100644 index 9daf8e09e..000000000 --- a/src/routes/solid-start/v2/(0)index.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Overview -titleTemplate: ":title" -use_cases: >- - getting started, new projects, learning solidstart, framework overview, - architecture decisions -tags: - - overview - - introduction - - getting-started - - routing - - server -version: "2.0" -description: >- - SolidStart v2 overview: routing, server functions, HTTP helpers, and - Vite-based configuration. ---- - -SolidStart v2 builds a full-stack app on top of [Solid v1](/) and [Vite v8+](https://vite.dev). If you're currently using SolidStart v1, it's mainly a tooling and stability upgrade. - -What's new in SolidStart v2 is that it uses Vite's Environment API for client and server builds and therefore works with deployment plugins such as [Nitro v3](https://nitro.build), the [Cloudflare Vite plugin](https://developers.cloudflare.com/workers/vite-plugin/), and the [Netlify Vite plugin](https://docs.netlify.com/build/frameworks/framework-setup-guides/solidstart/). - -SolidStart is router agnostic, and can be used with either the official [Solid Router v1](/solid-router) or [TanStack Solid Router v1](https://tanstack.com/router/latest). - -## Migrating from SolidStart v1 - -If you are upgrading an existing app, start with the [migration guide](/solid-start/v2/migrating-from-v1). diff --git a/src/routes/solid-start/v2/(1)advanced/(0)middleware.mdx b/src/routes/solid-start/v2/(1)advanced/(0)middleware.mdx deleted file mode 100644 index ab3e7c51b..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(0)middleware.mdx +++ /dev/null @@ -1,155 +0,0 @@ ---- -title: Middleware -use_cases: >- - request interception, header management, global data sharing, request - preprocessing, logging, redirects -tags: - - middleware - - headers - - interceptors - - logging - - preprocessing - - locals -version: "2.0" -description: >- - Compose H3 v2 middleware for authentication, logging, headers, and - request-scoped data in SolidStart. ---- - -Middleware runs around SolidStart's request handler. It is useful for logging, redirects, request preprocessing, response headers, and initializing request-scoped data. - -Do not rely on middleware alone for authorization. Client-side navigation can reuse data and server functions independently of a page request, so authorization must also be enforced close to each protected query, action, or API route. - -## Configure middleware - -Create a middleware module and pass its path to `solidStart()`. - -```ts title="src/middleware/index.ts" -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware([ - async (event, next) => { - console.log("Request received:", event.req.url); - const startedAt = Date.now(); - - const response = await next(); - - console.log(`Request took ${Date.now() - startedAt}ms`); - return response; - }, -]); -``` - -```tsx title="vite.config.ts" {7} -import { nitro } from "nitro/vite"; -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [solidStart({ middleware: "./src/middleware/index.ts" }), nitro()], -}); -``` - -Each entry is an [H3 middleware](https://h3.dev/guide/basics/middleware). Code before `await next()` runs before the downstream handler. Code after it runs as the response unwinds. - -## Request-scoped locals - -SolidStart decorates configured middleware with its request context. Use `getRequestEvent()` to read or update `event.locals` for later server code. - -```ts title="src/middleware/index.ts" -import { createMiddleware } from "@solidjs/start/middleware"; -import { getRequestEvent } from "solid-js/web"; - -export default createMiddleware([ - async (_event, next) => { - const requestEvent = getRequestEvent(); - if (requestEvent) { - requestEvent.locals.requestId = crypto.randomUUID(); - } - return next(); - }, -]); -``` - -Augment `App.RequestEventLocals` to type custom fields. See [Request events](/solid-start/v2/advanced/request-events#locals). - -## Headers and cookies - -H3 v2 uses Web standard `Request`, `Response`, and `Headers` objects. You can access them through the H3 event or use SolidStart's context-aware HTTP helpers. - -```ts title="src/middleware/index.ts" -import { getCookie, setCookie } from "@solidjs/start/http"; -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware([ - async (event, next) => { - const theme = getCookie("theme") ?? "system"; - setCookie("theme", theme, { - httpOnly: true, - secure: true, - sameSite: "lax", - }); - - const response = await next(); - event.res.headers.set("x-theme", theme); - return response; - }, -]); -``` - -`@solidjs/start/http` and `@solidjs/start/middleware` are server-only entrypoints. Importing them from client-reachable code causes a clear development or build error. - -## Short-circuit the request - -Return a `Response` before calling `next()` to stop the chain. - -```ts -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware([ - (event, next) => { - if (!event.req.headers.get("authorization")) { - return new Response("Unauthorized", { status: 401 }); - } - return next(); - }, -]); -``` - -Redirect responses from Solid Router work the same way: - -```ts -import { redirect } from "@solidjs/router"; -import { createMiddleware } from "@solidjs/start/middleware"; - -export default createMiddleware([ - (event, next) => { - if (new URL(event.req.url).pathname === "/login") { - return redirect("/auth/login", 301); - } - return next(); - }, -]); -``` - -## Middleware order - -Middleware uses an onion model. Before-`next()` logic runs in declaration order; after-`next()` logic runs in reverse order. - -The v1 object form with `onRequest` and `onBeforeResponse` remains available for migration but is deprecated. In `2.0.0`, deprecated `onBeforeResponse` arrays run in their declared order. Remove any manual reversal added as a workaround for earlier prereleases. - -## Custom H3 handlers - -The experimental `decorateHandler` and `decorateMiddleware` exports from `@solidjs/start/server` provide Solid's request context to custom H3 code that runs outside the configured middleware chain. - -```ts -import { decorateHandler } from "@solidjs/start/server"; -import { defineHandler } from "nitro"; - -export default defineHandler( - decorateHandler(() => { - // getRequestEvent() is available here - return { ok: true }; - }) -); -``` diff --git a/src/routes/solid-start/v2/(1)advanced/(1)session.mdx b/src/routes/solid-start/v2/(1)advanced/(1)session.mdx deleted file mode 100644 index a0ce18f57..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(1)session.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: Sessions -use_cases: >- - user sessions, authentication state, preferences storage, stateful - interactions, login persistence -tags: - - sessions - - cookies - - authentication - - state - - storage - - persistence -version: "2.0" -description: >- - Manage encrypted cookie sessions with the SolidStart HTTP helpers. ---- - -Sessions let the server associate state with multiple requests from the same browser. SolidStart exposes H3 v2's encrypted cookie-session helpers through `@solidjs/start/http`. - -Session helpers are server-only. Use them from server functions, API routes, middleware, or other server-only modules. - -## Create a session helper - -`useSession` reads the current session and returns methods for updating or clearing it. - -```ts title="src/lib/session.ts" -import { useSession } from "@solidjs/start/http"; - -type SessionData = { - userId?: string; - theme?: "light" | "dark"; -}; - -export function useAppSession() { - "use server"; - - return useSession({ - name: "app-session", - password: process.env.SESSION_SECRET as string, - cookie: { - httpOnly: true, - secure: process.env.NODE_ENV === "production", - sameSite: "lax", - }, - }); -} -``` - -Use a secret of at least 32 characters and store it in a private environment variable. Generate one with: - -```sh frame="none" -openssl rand -base64 32 -``` - -## Read session data - -```ts -export async function getCurrentUserId() { - "use server"; - const session = await useAppSession(); - return session.data.userId ?? null; -} -``` - -## Update session data - -```ts -export async function setTheme(theme: "light" | "dark") { - "use server"; - const session = await useAppSession(); - await session.update({ theme }); -} -``` - -## Clear a session - -```ts -export async function logout() { - "use server"; - const session = await useAppSession(); - await session.clear(); -} -``` - -In addition to `useSession`, `@solidjs/start/http` exports `getSession`, `updateSession`, `clearSession`, `sealSession`, and `unsealSession` for lower-level workflows. - -Cookie sessions should contain small, non-sensitive identifiers and preferences. For revocation, device management, or larger data, store the session record in a database and keep only its opaque ID in the cookie. diff --git a/src/routes/solid-start/v2/(1)advanced/(2)request-events.mdx b/src/routes/solid-start/v2/(1)advanced/(2)request-events.mdx deleted file mode 100644 index 39e9cc755..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(2)request-events.mdx +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Request events -use_cases: >- - server context access, local data storage, request handling, server functions, - event access -tags: - - events - - server - - context - - locals - - requests - - functions -version: "2.0" -description: >- - Access request events, typed locals, and the native H3 v2 event in SolidStart. ---- - -Call [`getRequestEvent`](/reference/server-utilities/get-request-event) from `solid-js/web` to access the current request in server-rendering, API, middleware, query, and action code. - -```tsx -import { getRequestEvent } from "solid-js/web"; - -const event = getRequestEvent(); -const request = event?.request; -``` - -`getRequestEvent()` returns `undefined` outside a request context. - -## Locals - -`event.locals` is request-scoped storage shared by SolidStart middleware and server code. Add your fields to the global `App.RequestEventLocals` interface: - -```tsx title="src/env.d.ts" -declare namespace App { - interface RequestEventLocals { - user?: { id: string }; - requestId: string; - } -} -``` - -The `@solidjs/start/env` type entry provides the base namespace and should be included in `tsconfig.json`. - -```json title="tsconfig.json" -{ - "compilerOptions": { - "types": ["@solidjs/start/env"] - } -} -``` - -## Native event - -`event.nativeEvent` is the underlying H3 v2 event. It exposes Web standard request and response objects as `event.nativeEvent.req` and `event.nativeEvent.res`. - -Most application code does not need the native event. Prefer `event.request`, `event.response`, or a helper from `@solidjs/start/http`. The HTTP entrypoint is server-only, so import it only from server code or inside a function marked with `"use server"`. diff --git a/src/routes/solid-start/v2/(1)advanced/(3)return-responses.mdx b/src/routes/solid-start/v2/(1)advanced/(3)return-responses.mdx deleted file mode 100644 index adaf4b94c..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(3)return-responses.mdx +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Returning responses -use_cases: >- - server function responses, error handling, response types, api responses, - typescript typing -tags: - - responses - - server - - functions - - typescript - - errors - - api -version: "2.0" -description: >- - Return typed Response objects from server functions. Handle redirects, - reloads, and JSON responses with proper TypeScript support. ---- - -In SolidStart, it is possible to return a Response object from a server function. -[`solid-router`](/solid-router) knows how to handle certain responses with its [`query`](/solid-router/reference/data-apis/query) and [`action`](/solid-router/reference/data-apis/action) APIs. -For TypeScript, when returning a response using `solid-router`'s `redirect`, `reload`, or `json` helpers, they will not impact the return value of the server function. - -While we suggest depending on the type of the function to handle errors differently, you can always return or throw a response. - -## Examples - -In the following example, the `hello` function will return a value of type `Promise<{ hello: string }>`: - -```tsx -import { json } from "@solidjs/router"; -import { GET } from "@solidjs/start"; - -const hello = GET(async (name: string) => { - "use server"; - return json( - { hello: new Promise((r) => setTimeout(() => r(name), 1000)) }, - { headers: { "cache-control": "max-age=60" } } - ); -}); -``` - -However, in this example, since `redirect` and `reload` return `never` as their type, `getUser` can only return a value of type `Promise`: - -```tsx { 4, 10, 14} -export async function getUser() { - "use server"; - - const session = await getSession(); - const userId = session.data.userId; - if (userId === undefined) return redirect("/login"); - - try { - const user: User = await db.user.findUnique({ where: { id: userId } }); - // throwing can be awkward. - if (!user) return redirect("/login"); - return user; - } catch { - // do stuff - throw redirect("/login"); - } -} -``` diff --git a/src/routes/solid-start/v2/(1)advanced/(4)serialization.mdx b/src/routes/solid-start/v2/(1)advanced/(4)serialization.mdx deleted file mode 100644 index 42e57111f..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(4)serialization.mdx +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: Serialization -use_cases: >- - server function payloads, data transfer, custom types, seroval plugins, csp, - security, performance -tags: - - serialization - - server-functions - - csp - - security - - performance -version: "2.0" -description: >- - How SolidStart serializes server function payloads and the CSP tradeoff - between json and js modes. ---- - -Server function arguments and return values are serialized so they can travel between server and client. - -## Configuration - -Set the mode on `solidStart()` in `vite.config.ts`: - -```tsx title="vite.config.ts" -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [ - solidStart({ - serialization: { mode: "json" }, - }), - ], -}); -``` - -## Modes - -- `json`: deserializes with `JSON.parse` on the client. It avoids `eval`, so it fits a strict CSP. This is the default. -- `js`: a smaller binary format that needs `eval` on the client, which a strong CSP blocks. - -If your app enforces a Content Security Policy, keep `json`. - -## Temporal values - -SolidStart preserves JavaScript [`Temporal`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal) values in server function and action payloads. The value is reconstructed as the same Temporal type on the receiving side. - -SolidStart does not install a Temporal implementation. Native server-runtime availability is: - -| Runtime | Unflagged global `Temporal` support | -| ------- | ---------------------------------------------------------------- | -| Node.js | [26 and later](https://nodejs.org/en/blog/release/v26.0.0/) | -| Deno | [2.7 and later](https://deno.com/blog/v2.7) | -| Bun | [No stable release](https://github.com/oven-sh/bun/issues/15853) | - -Server-runtime support does not guarantee browser support. Both the client and server must provide a compatible global `Temporal` before a payload is serialized or deserialized. Check `typeof globalThis.Temporal !== "undefined"` in each target environment. - -If any runtime targeted by your app does not provide `Temporal` natively, install a global polyfill: - -```sh -pnpm add temporal-polyfill -``` - -```ts title="src/temporal.ts" -import "temporal-polyfill/global"; -``` - -Import the shared module before application initialization in both entrypoints: - -```tsx title="src/entry-client.tsx and src/entry-server.tsx" -import "./temporal"; -``` - -Use the polyfill's global entrypoint. A local import such as `import { Temporal } from "temporal-polyfill"` does not define the global that serialization requires. Without a compatible global on either side, sending a Temporal value causes serialization or deserialization to fail. - -## Custom types - -Use a custom Seroval plugin when a server function needs to accept or return a value that Seroval does not support, such as a database identifier, decimal type, or another custom class. - -Set `serialization.plugins` to a module whose default export is an array of plugins: - -```tsx title="vite.config.ts" -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [ - solidStart({ - serialization: { - plugins: "src/seroval-plugins.ts", - }, - }), - ], -}); -``` - -Create plugins with the API exported by `@solidjs/start/serialization`. The entrypoint exports `createPlugin`, `OpaqueReference`, and the related plugin types. Importing from it keeps the plugin on the same Seroval version that SolidStart uses. - -```ts title="src/seroval-plugins.ts" -import { createPlugin } from "@solidjs/start/serialization"; -import { Money } from "./lib/money"; - -const moneyPlugin = createPlugin({ - tag: "app/Money", - test: (value) => value instanceof Money, - parse: { - sync: (value, ctx) => ({ cents: ctx.parse(value.cents) }), - async: async (value, ctx) => ({ - cents: await ctx.parse(value.cents), - }), - stream: (value, ctx) => ({ cents: ctx.parse(value.cents) }), - }, - serialize: (node, ctx) => - `new globalThis.Money(${ctx.serialize(node.cents)})`, - deserialize: (node, ctx) => new Money(ctx.deserialize(node.cents) as number), -}); - -export default [moneyPlugin]; -``` - -SolidStart bundles the plugin module into both the client and server builds, so it must not import server-only code. Built-in SolidStart plugins run before custom plugins. - -Custom plugins apply to server function and action payloads. They do not affect the hydration payload produced by `solid-js/web`. - -With the default `json` mode, `deserialize` rebuilds the value. If you use `js` mode, the code returned by `serialize` can only refer to globals available in the client. In the example above, `Money` must be assigned to `globalThis.Money` before deserialization. - -## Server function payloads - -SolidStart applies extra handling for certain payload types so file uploads and binary data can flow without being serialized by Seroval. This applies to both server function arguments and return values. SolidStart bypasses Seroval for: - -- `FormData` -- `URLSearchParams` -- `Uint8Array` -- `ArrayBuffer` -- `Blob` -- `File` -- `string` - -Because these values are transferred directly, this can yield smaller payloads for these cases. - -## Related - -- [Data fetching](/solid-start/v2/building-your-application/data-fetching) -- [Data mutation](/solid-start/v2/building-your-application/data-mutation) diff --git a/src/routes/solid-start/v2/(1)advanced/(5)auth.mdx b/src/routes/solid-start/v2/(1)advanced/(5)auth.mdx deleted file mode 100644 index b711a3ced..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(5)auth.mdx +++ /dev/null @@ -1,61 +0,0 @@ ---- -title: Auth -use_cases: >- - user authentication, protected routes, authorization checks, secure data - access, login systems -tags: - - authentication - - authorization - - security - - protected - - login - - users -version: "2.0" -description: >- - Implement authentication and protected routes in SolidStart. Secure sensitive - resources and handle user authorization properly. ---- - -Server functions can be used to protect sensitive resources like user data. - -```tsx -"use server"; - -async function getPrivatePosts() { - const user = await getUser(); - if (!user) { - return null; // or throw an error - } - - return db.getPosts({ userId: user.id, private: true }); -} -``` - -The `getUser` function can be [implemented using sessions](/solid-start/v2/advanced/session). - -## Protected Routes - -Routes can be protected by checking the user or session object during data fetching. -This example uses [Solid Router](/solid-router). - -```tsx -const getPrivatePosts = query(async function () { - "use server"; - const user = await getUser(); - if (!user) { - throw redirect("/login"); - } - - return db.getPosts({ userId: user.id, private: true }); -}); - -export default function Page() { - const posts = createAsync(() => getPrivatePosts(), { deferStream: true }); -} -``` - -Once the user hits this route, the router will attempt to fetch `getPrivatePosts` data. -If the user is not signed in, `getPrivatePosts` will throw and the router will redirect to the login page. - -To prevent errors when opening the page directly, set `deferStream: true`. -This would ensure `getPrivatePosts` resolves before the page loads since server-side redirects cannot occur after streaming has started. diff --git a/src/routes/solid-start/v2/(1)advanced/(6)websocket.mdx b/src/routes/solid-start/v2/(1)advanced/(6)websocket.mdx deleted file mode 100644 index bcfebcf15..000000000 --- a/src/routes/solid-start/v2/(1)advanced/(6)websocket.mdx +++ /dev/null @@ -1,72 +0,0 @@ ---- -title: WebSocket endpoint -use_cases: >- - real-time updates, chat applications, live notifications, multiplayer games, - collaborative editing, streaming data -tags: - - websocket - - real-time - - streaming - - server - - events -version: "2.0" -description: >- - Add a Nitro v3 WebSocket endpoint to a SolidStart application. ---- - -SolidStart v2 uses Nitro v3's cross-platform WebSocket support. Enable the feature in Nitro's Vite configuration and define the endpoint as a Nitro server route. - -## Enable WebSockets - -```tsx title="vite.config.ts" -import { nitro } from "nitro/vite"; -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [solidStart(), nitro()], - nitro: { - serverDir: "./server", - features: { - websocket: true, - }, - }, -}); -``` - -## Create an endpoint - -Files in `server/routes` use Nitro's file-based server routing. This example handles connections at `/ws`. - -```ts title="server/routes/ws.ts" -import { defineWebSocketHandler } from "nitro"; - -export default defineWebSocketHandler({ - open(peer) { - console.log("open", peer.id); - peer.send("Connected"); - }, - message(peer, message) { - console.log("message", peer.id, message.text()); - peer.send(message.text()); - }, - close(peer, details) { - console.log("close", peer.id, details.code, details.reason); - }, - error(peer, error) { - console.error("websocket error", peer.id, error); - }, -}); -``` - -Connect with the browser WebSocket API: - -```ts -const protocol = location.protocol === "https:" ? "wss:" : "ws:"; -const socket = new WebSocket(`${protocol}//${location.host}/ws`); - -socket.addEventListener("open", () => socket.send("Hello")); -socket.addEventListener("message", (event) => console.log(event.data)); -``` - -Nitro also supports upgrade hooks, peer context, topics, namespaces, and pub/sub. See the [Nitro WebSocket guide](https://nitro.build/docs/websocket). diff --git a/src/routes/solid-start/v2/(1)getting-started.mdx b/src/routes/solid-start/v2/(1)getting-started.mdx deleted file mode 100644 index 456f74d01..000000000 --- a/src/routes/solid-start/v2/(1)getting-started.mdx +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: Getting started -use_cases: >- - new project, initial setup, project creation, starter template, first app, - quick start, bootstrapping -tags: - - setup - - installation - - starter - - template - - quickstart -version: "2.0" -description: >- - Start a SolidStart v2 project with create-solid and configure the Vite - plugin. ---- - -The easiest way to start a new SolidStart project is with `create-solid`. -SolidStart v2 requires Node.js 24 or newer. - -## Create a project - -Create a new app with the Solid scaffolding tool: - -```package-create -solid -``` - -Follow the interactive prompts and choose the SolidStart template or an official example that matches your use case. - -After the project is created, install dependencies: - -```package-install-local - -``` - -Then start the development server: - -```package-run -dev -``` - -## Configuration - -Configuration lives in `vite.config.ts`. Start with the `solidStart()` plugin, which configures the application: - -```tsx title="vite.config.ts" -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [solidStart()], -}); -``` - -If your app already has middleware, `solidStart()` also accepts a `middleware` option: - -```tsx title="vite.config.ts" -import { defineConfig } from "vite"; -import { solidStart } from "@solidjs/start/config"; - -export default defineConfig({ - plugins: [solidStart({ middleware: "./src/middleware/index.ts" })], -}); -``` - -To configure a production server runtime and hosting target, continue with [Deployment plugins](/solid-start/v2/guides/deployment-plugins). - -## Path alias - -SolidStart provides a built-in `~` alias for the application root. With the default [`appRoot`](/solid-start/v2/reference/config/solid-start#approot), an import from `~/lib/db` resolves to `src/lib/db`. - -```ts -import { db } from "~/lib/db"; -``` - -## Development toolbar - -During development, SolidStart adds a toolbar for inspecting application errors and server function calls. The toolbar is not included in production builds. - -To hide it during development, set `devOverlay` to `false`: - -```tsx title="vite.config.ts" -solidStart({ devOverlay: false }); -``` - -## Start adding routes - -The filesystem router reads files from your routes directory and turns them into UI routes or API routes. -For example: - -- `src/routes/index.tsx` becomes `/` -- `src/routes/about.tsx` becomes `/about` -- `src/routes/api/ping.ts` can expose `/api/ping` - -Read [Routing](/solid-start/v2/building-your-application/routing) next if you want the exact filename conventions. - -## Type support - -Environment types ship in `@solidjs/start/env`. -Add it to your TypeScript config if your template has not already done so. - -```json -{ - "compilerOptions": { - "types": ["@solidjs/start/env"] - } -} -``` - -If you are migrating an existing app instead of creating a new one, continue with [Migrating from v1](/solid-start/v2/migrating-from-v1). diff --git a/src/routes/solid-start/v2/(2)guides/(0)security.mdx b/src/routes/solid-start/v2/(2)guides/(0)security.mdx deleted file mode 100644 index 88feed732..000000000 --- a/src/routes/solid-start/v2/(2)guides/(0)security.mdx +++ /dev/null @@ -1,220 +0,0 @@ ---- -title: Security -use_cases: >- - production apps, user input handling, authentication, public apis, preventing - attacks, secure deployments, compliance -tags: - - security - - xss - - csrf - - cors - - csp - - middleware - - protection -version: "2.0" -description: >- - Secure your SolidStart apps against XSS, CSRF attacks. Configure CSP headers, - CORS policies, and implement security best practices. ---- - -## XSS (Cross Site Scripting) - -Solid automatically escapes values passed to JSX expressions to reduce the risk of XSS attacks. -However, this protection does not apply when using [`innerHTML`](/reference/jsx-attributes/innerhtml). - -To protect your application from XSS attacks: - -- Set a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). -- Validate and sanitize user inputs, especially form inputs on the server and client. -- Avoid using `innerHTML` when possible. - If necessary, make sure to sanitize user-supplied data with libraries such as [DOMPurify](https://github.com/cure53/DOMPurify). -- Sanitize attributes containing user-supplied data within `