{"id":13565191,"url":"https://github.com/dmjio/miso","last_synced_at":"2025-05-13T15:09:06.944Z","repository":{"id":22165343,"uuid":"61973641","full_name":"dmjio/miso","owner":"dmjio","description":":ramen: A tasty Haskell front-end framework","archived":false,"fork":false,"pushed_at":"2025-05-08T14:22:28.000Z","size":2567,"stargazers_count":2259,"open_issues_count":11,"forks_count":144,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-05-08T14:41:01.995Z","etag":null,"topics":["ghc","ghcjs","haskell","javascript","miso","nix","ramen","ui","virtual-dom","wasm","web-assembly"],"latest_commit_sha":null,"homepage":"https://haskell-miso.org","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmjio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"open_collective":"miso","github":"dmjio"}},"created_at":"2016-06-26T04:28:54.000Z","updated_at":"2025-05-08T14:22:28.000Z","dependencies_parsed_at":"2023-10-01T17:24:27.264Z","dependency_job_id":"b2b34cda-82e0-4070-a6a1-40f64536587e","html_url":"https://github.com/dmjio/miso","commit_stats":{"total_commits":653,"total_committers":61,"mean_commits":"10.704918032786885","dds":"0.23430321592649306","last_synced_commit":"0305b26472e7ed558334df69a6adadbd630eda25"},"previous_names":[],"tags_count":57,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmjio%2Fmiso","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmjio%2Fmiso/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmjio%2Fmiso/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmjio%2Fmiso/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmjio","download_url":"https://codeload.github.com/dmjio/miso/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253969238,"owners_count":21992262,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ghc","ghcjs","haskell","javascript","miso","nix","ramen","ui","virtual-dom","wasm","web-assembly"],"created_at":"2024-08-01T13:01:42.258Z","updated_at":"2025-05-13T15:09:06.928Z","avatar_url":"https://github.com/dmjio.png","language":"Haskell","readme":"\u003ch1 align=\"center\"\u003emiso\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\n\n\u003ca href=\"https://haskell-miso.org\"\u003e\n  \u003cimg width=10% src=\"https://em-content.zobj.net/thumbs/240/apple/325/steaming-bowl_1f35c.png\"\u003e\n   \u003c/a\u003e\n\u003cp align=\"center\"\u003eA \u003ci\u003etasty\u003c/i\u003e \u003ca href=\"https://www.haskell.org/\"\u003e\u003cstrong\u003eHaskell\u003c/strong\u003e\u003c/a\u003e front-end web framework 🍜\u003c/p\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://matrix.to/#/#haskell-miso:matrix.org\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/matrix.org-miso-E01563.svg?style=flat-square\" alt=\"Matrix #haskell-miso:matrix.org\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://haskell.org\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/language-Haskell-orange.svg?style=flat-square\" alt=\"Haskell\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://haskell-miso-cachix.cachix.org\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/build-cachix-yellow.svg?style=flat-square\" alt=\"Cachix\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://actions-badge.atrox.dev/dmjio/miso/goto?ref=master\"\u003e\n    \u003cimg alt=\"Build Status\" src=\"https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2Fdmjio%2Fmiso%2Fbadge%3Fref%3Dmaster\u0026style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://discord.gg/QVDtfYNSxq\"\u003e\n    \u003cimg alt=\"Discord\" src=\"https://img.shields.io/discord/1302720467232096358?style=flat-square\u0026label=discord\u0026logoColor=7289da\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"http://hackage.haskell.org/package/miso\"\u003e\n    \u003cimg src=\"https://img.shields.io/hackage/v/miso.svg?style=flat-square\" alt=\"Hackage\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/dmjio/miso/blob/master/LICENSE\"\u003e\n    \u003cimg src=\"http://img.shields.io/badge/license-BSD3-blueviolet.svg?style=flat-square\" alt=\"LICENSE\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n**Miso** is a small, production-ready, component-oriented, [isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/) [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, recursive diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, Server-sent events ([SSE](https://html.spec.whatwg.org/multipage/server-sent-events.html)), [Websockets](https://websockets.spec.whatwg.org/), type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/) and [React](http://react.dev/). **Miso** is pure by default, but side effects can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHC Javascript FFI](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html#javascript-ffi-in-the-wasm-backend) and therefore has minimal dependencies. **Miso** can be considered a shallow [embedded domain-specific language](https://wiki.haskell.org/Embedded_domain_specific_language) for modern web programming.\n\n**Miso** supports compilation to both [JavaScript](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/javascript.html) and [WebAssembly](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html) using [GHC](https://www.haskell.org/ghc/). For hot-reload, `miso` uses the [jsaddle](https://github.com/ghcjs/jsaddle) library. When used with [ghcid](https://github.com/ndmitchell/ghcid) and [ghciwatch](https://github.com/MercuryTechnologies/ghciwatch) this enables a rapid development workflow.\n\n\u003e [!TIP]\n\u003e [React-style Components](https://github.com/dmjio/miso/pull/766) are now added to `miso` as of version `1.9`. This has not yet been released, we recommend developing against `master` if you'd like to use latest features.\n\n## Table of Contents\n- [Quick Start](#quick-start)\n- [Setup](#setup)\n- [Hot Reload](#hot-reload)\n- [Compilation](#compilation)\n- [WebAssembly](#web-assembly)\n- [JavaScript](#JavaScript)\n- [Haddocks](#haddocks)\n- [Architecture](#architecture)\n- [Internals](#internals)\n- [Examples](#examples)\n- [Building examples](#building-examples)\n- [HTTP](#interacting-with-http-apis)\n- [Coverage](#coverage)\n- [Isomorphic](#isomorphic)\n- [Benchmarks](#benchmarks)\n- [Nix](#nix)\n  - [Pinning nixpkgs](#pinning-nixpkgs)\n  - [Binary cache](#binary-cache)\n- [Maintainers](#maintainers)\n- [Contributing](#contributing)\n- [Contributors](#contributors)\n- [Partnerships](#partnerships)\n- [Financial contributors](#financial-contributors)\n- [Organizations](#organizations)\n- [License](#license)\n\n## Quick start\nTo start developing applications with `miso` you will need to acquire [GHC](https://www.haskell.org/ghc/) and [cabal](https://www.haskell.org/cabal/). This can be done via [GHCup](https://www.haskell.org/ghcup/) or [Nix](https://nixos.org/).\n\n\u003e [!TIP]\n\u003e For new Haskell users we recommend using [GHCup](https://www.haskell.org/ghcup/) to acquire both [GHC](https://www.haskell.org/ghc/) and [cabal](https://www.haskell.org/cabal/)\n\n## Setup 🏗️\n\nTo develop and build your first `miso` application you will need 3 files:\n\n  - `cabal.project`\n  - `app.cabal`\n  - `Main.hs`\n\n### `cabal.project`\n\n```yaml\npackages:\n  .\n\nsource-repository-package\n  type: git\n  location: https://github.com/dmjio/miso\n  branch: master\n```\n\n### `app.cabal`\n\nWe recommend using at least `cabal-version: 2.2`, this will give you the [common sections](https://vrom911.github.io/blog/common-stanzas) feature which we will use later to allow multiple compilers to build our project (so we can target `WASM` and `JS` backends)\n\n```yaml\ncabal-version: 2.2\nname: app\nversion: 0.1.0.0\nsynopsis: Sample miso app\ncategory: Web\n\ncommon wasm\n  if arch(wasm32)\n    ghc-options:\n      -no-hs-main\n      -optl-mexec-model=reactor\n      \"-optl-Wl,--export=hs_start\"\n    cpp-options:\n      -DWASM\n\nexecutable app\n  import:\n    wasm\n  main-is:\n    Main.hs\n  build-depends:\n    base, miso\n  default-language:\n    Haskell2010\n```\n\n### `Main.hs`\n\nThis file contains a simple `miso` counter application.\n\n```haskell\n----------------------------------------------------------------------------\n{-# LANGUAGE OverloadedStrings #-}\n{-# LANGUAGE RecordWildCards   #-}\n{-# LANGUAGE LambdaCase        #-}\n{-# LANGUAGE CPP               #-}\n----------------------------------------------------------------------------\nmodule Main where\n----------------------------------------------------------------------------\nimport Miso\nimport Miso.String\nimport Miso.Lens\n----------------------------------------------------------------------------\n-- | Application model state\nnewtype Model = Model\n  { _counter :: Int\n  } deriving (Show, Eq)\n----------------------------------------------------------------------------\ncounter :: Lens Model Int\ncounter = lens _counter $ \\record field -\u003e record { _counter = field }\n----------------------------------------------------------------------------\n-- | Sum type for App events\ndata Action\n  = AddOne\n  | SubtractOne\n  | SayHelloWorld\n  deriving (Show, Eq)\n----------------------------------------------------------------------------\n-- | Entry point for a miso application\nmain :: IO ()\nmain = run (startApp app)\n----------------------------------------------------------------------------\n-- | WASM export, required when compiling w/ the WASM backend.\n#ifdef WASM\nforeign export javascript \"hs_start\" main :: IO ()\n#endif\n----------------------------------------------------------------------------\n-- | `defaultApp` takes as arguments the initial model, update function, view function\napp :: App Model Action\napp = defaultApp emptyModel updateModel viewModel\n----------------------------------------------------------------------------\n-- | Empty application state\nemptyModel :: Model\nemptyModel = Model 0\n----------------------------------------------------------------------------\n-- | Updates model, optionally introduces side effects\nupdateModel :: Action -\u003e Effect Model Action\nupdateModel = \\case\n  AddOne        -\u003e counter += 1\n  SubtractOne   -\u003e counter -= 1\n  SayHelloWorld -\u003e io $ do\n    consoleLog \"Hello World\"\n    alert \"Hello World\"\n----------------------------------------------------------------------------\n-- | Constructs a virtual DOM from a model\nviewModel :: Model -\u003e View Action\nviewModel x = div_ []\n  [ button_ [ onClick AddOne ] [ text \"+\" ]\n  , text $ ms (x ^. counter)\n  , button_ [ onClick SubtractOne ] [ text \"-\" ]\n  , button_ [ onClick SayHelloWorld ] [ text \"Alert Hello World!\" ]\n  ]\n----------------------------------------------------------------------------\n```\n\nNow that your project files are populated, development can begin.\n\n## Hot Reload\n\nWith `GHC` and `cabal` on `$PATH`, call `cabal repl`\n\n```bash\n$ cabal repl\n```\n\nYou should see the following output in your terminal.\n\n```bash\n[1 of 2] Compiling Main             ( Main.hs, interpreted )\nOk, one module loaded.\nghci\u003e\n```\n\nNow call the `main` function in the `GHCi` REPL.\n\n```bash\nghci\u003e main\nRunning on port 8008...\n\u003ca href=\"http://localhost:8008\"\u003erun\u003c/a\u003e\nghci\u003e\n```\n\n\u003e [!NOTE]\n\u003e The code running in this example is not compiled to JavaScript or WebAssembly, rather it is running the client side application on the server. It works by sending commands to a small javascript interpreter over a websocket to render elements on the page. This is provided by the [jsaddle](https://github.com/ghcjs/jsaddle) library.\n\nIf you visit [http://localhost:8008](http://localhost:8008), the application will be live. You can now edit `Main.hs`, call `:r` and `main` in `GHCi`, and the application will update on the screen.\n\n\u003e [!NOTE]\n\u003e Instead of typing `:r` and `main` manually inside of `GHCi` on every file change, you can use [ghcid](https://github.com/ndmitchell/ghcid) or [ghciwatch](https://github.com/MercuryTechnologies/ghciwatch) tools to do it automatically.\n\n\u003e [!TIP]\n\u003e For users accustomed to a react.js worfklow, we highly recommend using either `ghcid` or `ghciwatch`.\n\nBelow is an example of usage with `ghcid`\n\n```bash\n$ ghcid -c 'cabal repl app' -T=Main.main\n```\n\nThis screenshot shows the hot-reload functionality in action. This is using `ghcid`, `jsaddle` and `miso`.\n\n![Image](https://github.com/user-attachments/assets/4c5e7191-e4a9-4270-a28b-2f5f71ad6f40)\n\n## Compilation\n\nWhen done developing, we can compile to Web Assembly or JavaScript for distribution. This is done by acquiring a `GHC` that supports WebAssembly or JavaScript. We recommend acquiring these backends using `GHCUp` or `Nix`.\n\n\u003e [!TIP]\n\u003e For new Haskell users we recommend using [GHCup](https://www.haskell.org/ghcup/) to acquire the [WASM](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html) and [JS](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/javascript.html) backends.\n\n## ![Image](https://github.com/user-attachments/assets/c57d96b2-368b-410e-b968-28dfe22bf1b1) Web Assembly\n\n\u003e [!TIP]\n\u003e The Haskell `miso` team currently recommends using the WASM backend as the default backend for compilation.\n\nUsing [GHCup](https://www.haskell.org/ghcup/) you should be able to acquire the `GHC` `WASM` compiler.\n\nFor instructions on how to add a third-party channel with [GHCup](https://www.haskell.org/ghcup/), please see their official [README.md](https://gitlab.haskell.org/haskell-wasm/ghc-wasm-meta#using-ghcup)\n\n\u003e [!TIP]\n\u003e For [Nix](nixos.org) users it is possible to acquire the WASM backend via a [Nix flake](https://nixos-and-flakes.thiscute.world/)\n\n```bash\n$ nix shell 'gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org'\n```\n\n\u003e [!NOTE]\n\u003e This will put `wasm32-wasi-cabal` in your `$PATH`, along with `wasm32-wasi-ghc`. Since the WASM backend is relatively new, the ecosystem is not entirely patched to support it. Therefore, we will need to use patched packages from time to time.\n\n\u003e [!TIP]\n\u003e Instead of using a `nix shell`, it's possible to install the GHC WASM Flake into your environment so it will always be present on `$PATH`\n\n```bash\n$ nix profile install 'gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org'\n```\n\nUpdate your `cabal.project` to the following\n\n- `cabal.project`\n\n```yaml\npackages:\n  .\n\nwith-compiler:\n  wasm32-wasi-ghc\n\nwith-hc-pkg:\n  wasm32-wasi-ghc-pkg\n\nsource-repository-package\n  type: git\n  location: https://github.com/dmjio/miso\n  branch: master\n\nif arch(wasm32)\n  -- Required for TemplateHaskell. When using wasm32-wasi-cabal from\n  -- ghc-wasm-meta, this is superseded by the global cabal.config.\n  shared: True\n\n  -- https://github.com/haskellari/splitmix/pull/73\n  source-repository-package\n    type: git\n    location: https://github.com/amesgen/splitmix\n    tag: cea9e31bdd849eb0c17611bb99e33d590e126164\n```\n\nCall `wasm32-wasi-cabal build --allow-newer` and a `WASM` payload should be created in `dist-newstyle/` directory.\n\n```bash\n$ wasm32-wasi-cabal update\n$ wasm32-wasi-cabal build --allow-newer\n```\n\n```bash\nConfiguration is affected by the following files:\n- cabal.project\nResolving dependencies...\nBuild profile: -w ghc-9.12.2.20250327 -O1\nIn order, the following will be built (use -v for more details):\n - app-0.1.0.0 (exe:app) (configuration changed)\nConfiguring executable 'app' for app-0.1.0.0...\nPreprocessing executable 'app' for app-0.1.0.0...\nBuilding executable 'app' for app-0.1.0.0...\n[1 of 1] Compiling Main             ( Main.hs, dist-newstyle/build/wasm32-wasi/ghc-9.12.2.20250327/app-0.1.0.0/x/app/build/app/app-tmp/Main.o )\n[2 of 2] Linking dist-newstyle/build/wasm32-wasi/ghc-9.12.2.20250327/app-0.1.0.0/x/app/build/app/app.wasm\n```\n\nYou have now successfully compiled a Haskell `miso` application to WebAssembly 🔥\n\n***\n\nBut, we're not done yet. In order to view this in the browser there are still a few more steps. We need to add some additional files that emulate the [WASI interface](https://github.com/WebAssembly/WASI) in the browser ([A browser WASI shim](https://github.com/bjorn3/browser_wasi_shim)).\n\n\u003e [!NOTE]\n\u003e The GHC WASM backend can execute any Haskell program in a WASI-compliant runtime (e.g. [wasmtime](https://github.com/bytecodealliance/wasmtime))\n\u003e See the [official documentation](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html) for more information.\n\nTo start, we recommend creating an `app.wasmexe` folder to store the additional artifacts required.\n\n```bash\n# Creates the directory for hosting\n$ mkdir -v app.wasmexe\nmkdir: created directory 'app.wasmexe'\n\n# This command produces `ghc_wasm_jsffi.js`, which ensures our FFI works properly.\n$ $(wasm32-wasi-ghc --print-libdir)/post-link.mjs \\\n   --input $(wasm32-wasi-cabal list-bin app --allow-newer) \\\n   --output app.wasmexe/ghc_wasm_jsffi.js\n\n# This copies the `app.wasm` payload into `app.wasmexe`\n$ cp -v $(wasm32-wasi-cabal list-bin app --allow-newer) app.wasmexe\nConfiguration is affected by the following files:\n- cabal.project\n'/home/dmjio/Desktop/miso/sample-app/dist-newstyle/build/wasm32-wasi/ghc-9.12.2.20250327/app-0.1.0.0/x/app/build/app/app.wasm' -\u003e 'app.wasmexe'\n```\n\n\u003e [!NOTE]\n\u003e Along with the above `ghc_wasm_jsffi.js` and `app.wasm` artifacts, we also need to include an `index.html` and an `index.js` for loading the WASM payload into the browser.\n\n- `index.html`\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\"\u003e\n    \u003ctitle\u003eSample miso WASM counter app\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cscript src=\"index.js\" type=\"module\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n- `index.js`\n\n```javascript\nimport { WASI, OpenFile, File, ConsoleStdout } from \"https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/dist/index.js\";\nimport ghc_wasm_jsffi from \"./ghc_wasm_jsffi.js\";\n\nconst args = [];\nconst env = [\"GHCRTS=-H64m\"];\nconst fds = [\n  new OpenFile(new File([])), // stdin\n  ConsoleStdout.lineBuffered((msg) =\u003e console.log(`[WASI stdout] ''${msg}`)),\n  ConsoleStdout.lineBuffered((msg) =\u003e console.warn(`[WASI stderr] ''${msg}`)),\n];\nconst options = { debug: false };\nconst wasi = new WASI(args, env, fds, options);\n\nconst instance_exports = {};\nconst { instance } = await WebAssembly.instantiateStreaming(fetch(\"app.wasm\"), {\n  wasi_snapshot_preview1: wasi.wasiImport,\n  ghc_wasm_jsffi: ghc_wasm_jsffi(instance_exports),\n});\nObject.assign(instance_exports, instance.exports);\n\nwasi.initialize(instance);\nawait instance.exports.hs_start(globalThis.example);\n```\n\nThe `app.wasmexe` folder will now look like:\n\n```\n❯ ls app.wasmexe\n app.wasm\n ghc_wasm_jsffi.js\n index.html\n index.js\n```\n\nNow you can host and view the `app.wasm` payload in a web browser.\n\n```\n$ http-server app.wasmexe\n```\n\n\u003e [!TIP]\n\u003e You can inspect the WASM payload in the `Sources` tab of your browser by right-clicking and then clicking `Inspect`.\n\n![Image](https://github.com/user-attachments/assets/41af274b-2c25-4b26-acb1-d2a5266cfa8a)\n\n## JavaScript\n\nUsing [GHCup](https://www.haskell.org/ghcup/) you should be able to acquire the latest GHC JS-backend compiler.\n\n\u003e [!TIP]\n\u003e For [Nix](https://nixos.org) users it is possible to acquire the latest JS backend (that `miso` uses) via Nix.\n\u003e Use [cachix](https://cachix.org) to ensure you're not building dependencies unnecessarily `cachix use haskell-miso-cachix`\n\n```bash\n❯ nix-shell -p pkgs.pkgsCross.ghcjs.haskell.packages.ghc9122.ghc -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/65f179f903e8bbeff3215cd613bdc570940c0eab.tar.gz\n```\n\n\u003e [!NOTE]\n\u003e This will put `javascript-unknown-ghcjs-ghc` in your `$PATH`, along with `javascript-unknown-ghcjs-ghc-pkg`. You might also need to specify in your `cabal.project` file that you are using the JS backend.\n\n\u003e [!TIP]\n\u003e Alternatively, if you'd like to install the compiler into your global environment (so you don't need to develop inside a `bash` shell) you can use the following command.\n\u003e\n\u003e ```bash\n\u003e ❯ nix-env -iA pkgs.pkgsCross.ghcjs.haskell.packages.ghc9122.ghc -f https://github.com/NixOS/nixpkgs/archive/65f179f903e8bbeff3215cd613bdc570940c0eab.tar.gz\n\u003e ```\n\n- `cabal.project`\n\n```yaml\npackages:\n  .\n\nsource-repository-package\n  type: git\n  location: https://github.com/dmjio/miso\n  branch: master\n\nwith-compiler:\n  javascript-unknown-ghcjs-ghc\n\nwith-hc-pkg:\n  javascript-unknown-ghcjs-ghc-pkg\n```\n\n\u003e [!NOTE]\n\u003e `cabal` will use the `ghc` specified above in `with-compiler`\n\n\n```bash\n$ cabal update \u0026\u0026 cabal build --allow-newer\n```\n\n```bash\nConfiguring executable 'app' for app-0.1.0.0...\nPreprocessing executable 'app' for app-0.1.0.0...\nBuilding executable 'app' for app-0.1.0.0...\n[1 of 1] Compiling Main             ( Main.hs, dist-newstyle/build/javascript-ghcjs/ghc-9.12.2/app-0.1.0.0/x/app/build/app/app-tmp/Main.o )\n[2 of 2] Linking dist-newstyle/build/javascript-ghcjs/ghc-9.12.2/app-0.1.0.0/x/app/build/app/app.jsexe\n\n```\n\n\u003e [!TIP]\n\u003e To view the JavaScript in your browser, you can use `cabal list-bin` and `http-server`\n\n```bash\n$ http-server $(cabal list-bin app --allow-newer).jsexe\nConfiguration is affected by the following files:\n- cabal.project\nStarting up http-server, serving /home/dmjio/Desktop/miso/sample-app/dist-newstyle/build/javascript-ghcjs/ghc-9.12.2/app-0.1.0.0/x/app/build/app/app.jsexe\n\nhttp-server version: 14.1.1\n\nhttp-server settings:\nCORS: disabled\nCache: 3600 seconds\nConnection Timeout: 120 seconds\nDirectory Listings: visible\nAutoIndex: visible\nServe GZIP Files: false\nServe Brotli Files: false\nDefault File Extension: none\n\nAvailable on:\n  http://127.0.0.1:8080\n  http://192.168.1.114:8080\nHit CTRL-C to stop the server\n```\n\n## Haddocks\n\nOffical [Haskell](https://haskell.org) documentation of the [Miso](https://haskell-miso.org) web framework.\n\n| Platform | URL |\n|------|-------------|\n| GHCJS | [Link](https://haddocks.haskell-miso.org/) |\n| GHC | [Link](http://hackage.haskell.org/package/miso) |\n\n\n## Architecture\n\nFor constructing client and server applications, we recommend using one `cabal` file with two executable sections, where the `buildable` attribute set is contingent on the compiler. An example of this layout is [here](https://github.com/dmjio/miso/blob/master/haskell-miso.org/haskell-miso.cabal#L24-L32).\n\n\u003e [!TIP]\n\u003e For more information on how to use `nix` with a `client`/`server` setup, see the [nix scripts](https://github.com/dmjio/miso/blob/master/haskell-miso.org/default.nix) for [https://haskell-miso.org](https://haskell-miso.org).\n\n## Internals ⚙️\n\nFor some details of the internals and general overview of how `miso` works, see the [Internals](docs/Internals.md).\n\n## Examples\n\nFor real-world examples of Haskell `miso` applications, see below.\n\n| Name            | Description                            | Source Link                                                                      | Live Demo Link                                | Author                               |\n|-----------------|----------------------------------------|----------------------------------------------------------------------------------|-----------------------------------------------|--------------------------------------|\n| **TodoMVC**     | A classic TodoMVC implementation       | [Source](https://github.com/dmjio/miso/blob/master/examples/todo-mvc/Main.hs)    | [Demo](https://todo-mvc.haskell-miso.org/)    | [@dmjio](https://github.com/dmjio)   |\n| **2048**        | A clone of the 2048 game               | [Source](https://github.com/ptigwe/hs2048/)                                      | [Demo](https://2048.haskell-miso.org/)        | [@ptigwe](https://github.com/ptigwe) |\n| **Flatris**     | A Tetris-like game                     | [Source](https://github.com/ptigwe/hs-flatris/)                                  | [Demo](https://flatris.haskell-miso.org/)     | [@ptigwe](https://github.com/ptigwe) |\n| **Plane**       | A flappy-birds-like game               | [Source](https://github.com/Lermex/miso-plane)                                   | [Demo](https://miso-plane.haskell-miso.org/)  | [@Lermex](https://github.com/Lermex) |\n| **Snake**       | The classic Snake game                 | [Source](https://github.com/lbonn/miso-snake)                                    | [Demo](https://snake.haskell-miso.org/)       | [@lbonn](https://github.com/lbonn)   |\n| **SVG**         | An example showcasing SVG rendering    | [Source](https://github.com/dmjio/miso/blob/master/examples/svg/Main.hs)         | [Demo](https://svg.haskell-miso.org/)         | [@dmjio](https://github.com/dmjio)   |\n| **Fetch**       | An example demonstrating AJAX requests | [Source](https://github.com/dmjio/miso/blob/master/examples/fetch/Main.hs)       | [Demo](https://fetch.haskell-miso.org/)       | [@dmjio](https://github.com/dmjio)   |\n| **File Reader** | A FileReader API example               | [Source](https://github.com/dmjio/miso/blob/master/examples/file-reader/Main.hs) | [Demo](https://file-reader.haskell-miso.org/) | [@dmjio](https://github.com/dmjio)   |\n| **WebGL**       | A 3D rendering example using Three.JS  | [Source](https://github.com/dmjio/miso/blob/master/examples/three/Main.hs)       | [Demo](https://threejs.haskell-miso.org/)     | [@dmjio](https://github.com/dmjio)   |\n| **Mario**       | A Super Mario physics example          | [Source](https://github.com/dmjio/miso/blob/master/examples/mario/Main.hs)       | [Demo](https://mario.haskell-miso.org/)       | [@dmjio](https://github.com/dmjio)   |\n| **WebSocket**   | A simple WebSocket example             | [Source](https://github.com/dmjio/miso/blob/master/examples/websocket/Main.hs)   | [Demo](https://websocket.haskell-miso.org/)   | [@dmjio](https://github.com/dmjio)   |\n| **Router**      | A client-side routing example          | [Source](https://github.com/dmjio/miso/blob/master/examples/router/Main.hs)      | [Demo](https://router.haskell-miso.org/)      | [@dmjio](https://github.com/dmjio)   |\n| **Canvas 2D**   | A 2D Canvas rendering example          | [Source](https://github.com/dmjio/miso/blob/master/examples/canvas2d/Main.hs)    | [Demo](https://canvas.haskell-miso.org/)      | [@dmjio](https://github.com/dmjio)   |\n\n## Building examples\n\nThe easiest way to build the examples is with the [`nix`](https://nixos.org/nix/) package manager\n\n\u003e [!TIP]\n\u003e Use [cachix](https://cachix.org) to ensure you're not building dependencies unnecessarily `cachix use haskell-miso-cachix`\n\n\n```\n$ git clone https://github.com/dmjio/miso\n$ cd miso\n$ nix-build -A miso-examples\n```\n\nThis will compile all the examples to JavaScript into a folder named `result`.\n\n```\n➜ tree -d ./result/bin\n./result/bin\n|-- canvas2d.jsexe\n|-- file-reader.jsexe\n|-- mario.jsexe\n|   `-- imgs\n|-- mathml.jsexe\n|-- router.jsexe\n|-- simple.jsexe\n|-- svg.jsexe\n|-- tests.jsexe\n|-- threejs.jsexe\n|-- todo-mvc.jsexe\n|-- websocket.jsexe\n`-- fetch.jsexe\n```\n\n\u003e [!NOTE]\n\u003e To see examples, we recommend hosting them with a web server (we use [http-server](https://github.com/http-party/http-server))\n\n```\ncd result/bin/todo-mvc.jsexe \u0026\u0026 http-sever\nServing HTTP on 0.0.0.0 port 8000 ...\n```\n\n## Interacting with HTTP APIs 🔌\n\nIf you want to interact with an HTTP API, we recommend one of the following approaches:\n\n  1. For a simple JSON-based API, you can use Miso's `fetchJSON` function.\n\n  2. In more complex cases, you can define a [Servant](https://www.servant.dev/) API and automatically obtain client functions via `servant-client-js` (or any other `servant-client-core`-based backend).\n\n     The Fetch example ([Source](https://github.com/dmjio/miso/blob/master/examples/fetch/Main.hs), [Demo](https://fetch.haskell-miso.org/)) demonstrates the necessary ingredients. Make sure to add the following to your `cabal.project`:\n\n     ```cabal\n     source-repository-package\n       type: git\n       location: https://github.com/amesgen/servant-client-js\n       tag: 2853fb4f26175f51ae7b9aaf0ec683c45070d06e\n     ```\n\n## Coverage ✅\n\nThe core engine of `miso` is the [diff](https://github.com/dmjio/miso/blob/master/ts/dom.ts) function. It is responsible for all DOM manipulation that occurs in a miso application and has [100% code coverage](http://coverage.haskell-miso.org). Tests and coverage made possible using [bun](https://github.com/oven-sh/bun).\n\n\u003e [!NOTE]\n\u003e To run the tests and build the coverage report ensure [bun](https://github.com/oven.sh/bun) is installed.\n\n```bash\n$ curl -fsSL https://bun.sh/install | bash\n```\nor\n\n```bash\n$ nix-env -iA bun -f '\u003cnixpkgs\u003e'\n```\n\nand\n\n```bash\n$ bun install \u0026\u0026 bun run test\n```\n\n```bash\n--------------------|---------|---------|-------------------\nFile                | % Funcs | % Lines | Uncovered Line #s\n--------------------|---------|---------|-------------------\nAll files           |   92.37 |   85.48 |\n ts/happydom.ts     |  100.00 |  100.00 |\n ts/miso/dom.ts     |  100.00 |  100.00 |\n ts/miso/event.ts   |   90.91 |   81.62 |\n ts/miso/hydrate.ts |   80.00 |   91.24 |\n ts/miso/smart.ts   |  100.00 |  100.00 |\n ts/miso/util.ts    |   83.33 |   40.00 |\n--------------------|---------|---------|-------------------\n\n 84 pass\n 0 fail\n```\n\n## Isomorphic ☯️\n\n[Isomorphic javascript](https://en.wikipedia.org/wiki/Isomorphic_JavaScript) is a technique for increased SEO, code-sharing and perceived page load times. It works in two parts. First, the server sends a pre-rendered HTML body to the client's browser. Second, after the client javascript application loads, the pointers of the pre-rendered DOM are copied into the virtual DOM (a process known as [hydration](https://en.wikipedia.org/wiki/Hydration_(web_development))), and the application proceeds as normal. All subsequent page navigation is handled locally by the client, while avoiding full-page postbacks.\n\n\u003e [!NOTE]\n\u003e The [miso](https://haddocks.haskell-miso.org/Miso.html#v:miso) function is used to facilitate the pointer-copying behavior client-side.\n\n## Benchmarks 🏎️\n\n[According to benchmarks](https://krausest.github.io/js-framework-benchmark/current.html), `miso` is among the fastest functional programming web frameworks, second only to [Elm](http://elm-lang.org).\n\n\u003ca target=\"_blank\" href=\"https://krausest.github.io/js-framework-benchmark/current.html\"\u003e\u003cimg src=\"https://cdn-images-1.medium.com/max/1600/1*6EjJTf1mhlTxd4QWsygCwA.png\" width=\"500\" height=\"600\" /\u003e\u003c/a\u003e\n\n## Nix \u003cimg src=\"https://raw.githubusercontent.com/NixOS/nixos-artwork/refs/heads/master/logo/nix-snowflake-colours.svg\" alt=\"nixos-snowflake\" width=\"25\"/\u003e\n\n`Nix` is a powerful option for building web applications with `miso` since it encompasses development workflow, configuration management, and deployment. The source code for [`haskell-miso.org`](https://github.com/dmjio/miso/tree/master/haskell-miso.org) is an example of this.\n\n\u003e [!TIP]\n\u003e If unfamiliar with `nix`, we recommend [@Gabriella439](https://github.com/Gabriella439)'s [\"Nix and Haskell in production\"](https://github.com/Gabriella439/haskell-nix) guide.\n\n### Pinning nixpkgs 📌\n\nBy default `miso` uses a known-to-work, pinned version of [`nixpkgs`](https://github.com/dmjio/miso/blob/master/nix/nixpkgs.json) known as `pkgs`.\n\n\u003e [!NOTE]\n\u003e `miso` also maintains a legacy version of nixpkgs known as `legacyPkgs` so we can use tools like `nixops` for deployment and to build `miso` with the original `GHCJS 8.6` backend.\n\n### Binary cache\n\n`nix` users on a Linux or OSX distros can take advantage of a [binary cache](https://haskell-miso-cachix.cachix.org) for faster builds. To use the binary cache follow the instructions on [cachix](https://haskell-miso-cachix.cachix.org/).\n\n\u003e [!TIP]\n\u003e We highly recommend nix users consume the [cachix](https://cachix.org) cache. `cachix use haskell-miso-cachix`.\n\n```bash\n$ cachix use haskell-miso-cachix\n```\n\n## Maintainers\n\n[@dmjio](https://github.com/dmjio)\n\n## Contributing\n\nFeel free to dive in! [Open an issue](https://github.com/dmjio/miso/issues/new) or a submit [Pull Request](https://github.com/dmjio/miso/pulls).\n\nSee [CONTRIBUTING](https://github.com/dmjio/miso/blob/master/CONTRIBUTING.md) for more info.\n\n## Contributors 🦾\n\n\u003e [!NOTE]\n\u003e This project exists thanks to all the people who [contribute](CONTRIBUTING.md)\n\n\u003ca href=\"https://github.com/dmjio/miso/graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/miso/contributors.svg?width=890\u0026button=false\" /\u003e\u003c/a\u003e\n\n## Partnerships 🤝\n\nIf you'd like to support this project financially, be it through requesting feature development, or a corporate partnership, please drop us a line and we will be in touch shortly. \u003cp\u003e\u003ca href=\"mailto:code@dmj.io\"\u003ecode@dmj.io\u003c/a\u003e\u003c/p\u003e\n\n## Financial contributors\n\nBecome a [financial contributor](https://opencollective.com/miso/contribute) and help us sustain our project and community. We are very grateful and thankful for our individual sponsors.\n\n  - Moses Tschanz\n  - [@MaxGabriel](https://github.com/MaxGabriel)\n  - [@DigitalOcean](https://github.com/DigitalOcean)\n  - [@maybetonyfu](https://github.com/maybetonyfu)\n  - [@jhrcek](https://github.com/jhrcek)\n  - etc.\n\n\u003ca href=\"https://opencollective.com/miso\"\u003e\u003cimg src=\"https://opencollective.com/miso/individuals.svg?width=890\"\u003e\u003c/a\u003e\n\n## Organizations\n\n[Support this project](https://opencollective.com/miso/contribute) with your organization. Your logo will show up here with a link to your website. We are also very grateful and thankful for our corporate sponsors.\n\n\u003ca target=\"_blank\" href=\"https://opencollective.com/miso/organization/0/website\"\u003e\u003cimg src=\"https://opencollective.com/miso/organization/0/avatar.svg\"\u003e\u003c/a\u003e\n\n## License\n\n[BSD3](LICENSE) © dmjio\n","funding_links":["https://opencollective.com/miso","https://github.com/sponsors/dmjio","https://opencollective.com/miso/contribute","https://opencollective.com/miso/organization/0/website"],"categories":["Haskell","前端开发框架及项目","Uncategorized","Inspired by Elm"],"sub_categories":["前端项目_其他","Uncategorized","Games"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmjio%2Fmiso","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmjio%2Fmiso","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmjio%2Fmiso/lists"}