Getting Started
Start hereSolidJS for modern OCaml.
solidtype is Solid for OCaml. A component is
written in OCaml’s JSX, compiled by Melange, and
reaches the browser as the code Solid’s own compiler emits for the same
JSX: the same templates, the same runtime calls, in the same order. What
OCaml adds is its types. A reactive read in the wrong place does not
compile, and neither does a prop left out, an attribute an element does not
take, or a match in a Switch that misses a case.
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsx
let make () = let count, set_count = S.create_signal 0 in <button class_="button button--primary" type_=`button on_click=(fun _ -> S.update set_count succ)> "Clicked " (fun () -> Jsx.int (S.get count)) " times" </button>What it is made of
Section titled “What it is made of”| Package | What it is |
|---|---|
solidtype |
Solid 1.9 bound whole: signals, computations, resources, stores, its components and its renderer, server rendering included |
ppx_solidtype |
rewrites JSX written in .mlx files into calls Melange compiles |
vite-plugin-solidtype |
turns those calls back into JSX, which Solid’s compiler compiles as it compiles TSX |
solidtype-kobalte |
Kobalte 0.13 bound whole, generated from its own declarations |
solidtype-heroui |
HeroUI’s design ported by hand onto Kobalte |
OCaml over TypeScript says why a front end is better written in OCaml. How it works follows one component through every step. Melange and dune and Vite and Astro say how each tool is set up, and Conventions how a name in Solid’s documentation is written in OCaml. The Solid and Kobalte tabs are the bindings, and HeroUI the components built on them.
Install
Section titled “Install”It needs opam, with a switch of OCaml 5.5 or later, and Bun 1.3 or later, which installs the JavaScript side and runs Vite 8.
The OCaml side, from Hypha’s opam repository:
opam repo add hypha https://github.com/hyphatech/opam-repository.gitopam install solidtype # and solidtype-kobalte for KobalteThe JavaScript side, with Vite and the plugin, which is an asset of each GitHub release:
{ "type": "module", "dependencies": { "solid-js": "~1.9.17", "vite": "^8.3.0", "vite-plugin-solid": "^2.11.14", "vite-plugin-solidtype": "https://github.com/hyphatech/solidtype/releases/download/0.3.0/vite-plugin-solidtype-0.3.0.tgz" }}A first page
Section titled “A first page”dune-project reads .mlx files, OCaml with JSX:
(lang dune 3.18)(using melange 0.1)(dialect (name mlx) (implementation (extension mlx) (merlin_reader mlx) (preprocess (run mlx-pp %{input-file}))))The components are a Melange library, emitted as .jsx modules, the files
the plugin rewrites:
; src/dune(library (name app) (modes melange) (libraries solidtype melange.dom) (preprocess (pps melange.ppx ppx_solidtype)))
; dune(melange.emit (target out) (libraries app) (module_systems (es6 jsx)))The counter above is src/app.mlx. An entry module mounts it,
src/main.ml:
external get_element_by_id : string -> Dom.element = "getElementById"[@@mel.scope "document"]
let (_ : unit -> unit) = Solidtype.Web.render App.make (get_element_by_id "app")The plugin runs before Solid’s:
import { defineConfig } from "vite";import solid from "vite-plugin-solid";import solidtype from "vite-plugin-solidtype";
export default defineConfig({ plugins: [solidtype(), solid()] });The page loads Melange’s output:
<!doctype html><div id="app"></div><script type="module" src="/_build/default/out/src/main.jsx"></script>Dune builds before Vite reads what it wrote:
bun installopam exec -- dune buildbun --bun vite build