From cb6ede1ab339daad234eef3bee21c5863f5b10cb Mon Sep 17 00:00:00 2001 From: Cheng Shao <terrorjack@type.dance> Date: Fri, 21 Mar 2025 03:46:06 +0000 Subject: [PATCH] docs: add wasm ghci subsection in user manual This commit updates the user manual to add wasm ghci subsection. (cherry picked from commit 6ef5c0d2498ee3ab7c547ca750b5c63c5733dfe4) (cherry picked from commit 9b1259b9a228bafefa203de87ffff3e4edecbf7f) --- docs/users_guide/wasm.rst | 101 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/docs/users_guide/wasm.rst b/docs/users_guide/wasm.rst index 95804e473b2..b5585e66be6 100644 --- a/docs/users_guide/wasm.rst +++ b/docs/users_guide/wasm.rst @@ -97,6 +97,107 @@ profiling functionality, then inspect the report files: $ wasmtime run --mapdir /::$PWD foo.wasm +RTS -hc -l -RTS +.. _wasm-ghci: + +Using GHCi with the wasm backend +-------------------------------- + +The GHC wasm backend supports the GHCi feature via a nodejs ``dyld`` +script that provides RTS linker functionality and bootstraps the +external interpreter. This script is installed into the +``wasm32-wasi-ghc --print-libdir`` location and will be automatically +launched by GHC when evaluating Template Haskell splices or starting +GHCi, though you do need a recent ``node`` available in ``PATH``. + +You can launch a GHCi session with ``wasm32-wasi-ghci`` or +``wasm32-wasi-ghc --interactive``. All existing GHCi features work with +wasm, including the GHCi debugger. You can also use JavaScript FFI +detailed in the next section; by default, the JavaScript FFI has access +to the nodejs global namespace since it runs in nodejs after all. + +Additionally, the wasm backend’s GHCi supports the browser mode to +allow live-coding the frontend using GHCi. This requires the `ws +<https://www.npmjs.com/package/ws>`__ library to be installed and +passed to the ``dyld`` script via the `NODE_PATH +<https://nodejs.org/api/modules.html>`__ environment variable. Suppose +your wasm backend installation is supplied by ``ghc-wasm-meta``, the +right ``node`` installation and ``NODE_PATH`` with all the optional +npm dependencies are automatically provided out of the box. + +To get started with the browser mode, set the ``GHCI_BROWSER`` +environment variable: + +:: + + $ export GHCI_BROWSER=1 + $ wasm32-wasi-ghc --interactive + GHCi, version 9.13.20250320: https://www.haskell.org/ghc/ :? for help + Open http://127.0.0.1:37517/main.html or import http://127.0.0.1:37517/main.js to boot ghci + +At this point, the GHCi session is frozen. The ``dyld`` script acts as a +broker between the host GHC process and the in-browser external +interpreter; it starts an HTTP server that serves ``main.js``, an ES6 +module that connects back to the HTTP server and finishes the rest of +external interpreter bootstrap process. The ``dyld`` HTTP server allows +`CORS <https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS>`__ +requests from any origin, meaning it’s possible to use F12 devtools +console to import ``main.js`` and use GHCi to debug other websites, but +the simplest way to get started is simply opening ``main.html`` in the +browser. + +After a few seconds, the GHCi session shall be unfrozen and available +for use. There are a few important points to keep in mind when using the +GHCi browser mode: + +- All the code runs in the browser, and the JavaScript FFI only has + access to the browser global namespace, not the nodejs one. There is + no escape hatch to invoke any function on the nodejs side. +- Likewise, the browser side has no access to the host filesystem. You + can use ``:load`` etc in the GHCi prompt to load modules just fine, + but attempting to do a ``readFile`` will fail, there is no file for + you to open in the browser-side virtual filesystem. +- Template Haskell splices are also evaluated in the browser. If your + splices require side-effects like reading files then they will fail to + evaluate; to workaround it, compile modules containing such splices to + object code first and load object code instead. +- By default, ``stdout``/``stderr`` doesn’t write back to the GHCi + prompt, the messages are written to the F12 devtools console in a + line-buffered manner. + +There are other options that can be specified as environment variables: + +- ``GHCI_BROWSER_HOST``: specify the host address that the ``dyld`` HTTP + server should bind to, supports IPv4/IPv6. Defaults to ``127.0.0.1``. + Be careful when changing it and exposing the ``dyld`` HTTP server to + other networks, some endpoints of the server allow downloading files + from the host filesystem! +- ``GHCI_BROWSER_PORT``: specify the port that the ``dyld`` HTTP server + should listen on. Defaults to a random idle port. +- ``GHCI_BROWSER_REDIRECT_WASI_CONSOLE``: if set to ``1``, the wasi + stdout/stderr output messages are redirected back to the host GHCi + terminal instead of outputing to the F12 devtools console. The main + intended use case is mobile browsers which likely don’t have F12 + devtools readily available. Also note that this only redirects wasi + console messages, not ``console.log`` invocations in the browser. + +For testing purposes, there is also support for using +`Puppeteer <https://pptr.dev>`__ or +`Playwright <https://playwright.dev>`__ to automatically launch a +headless browser and load ``main.html``. Like ``ws``, the relevant npm +dependencies need to be supplied via ``NODE_PATH``, either +``puppeteer``/``puppeteer-core`` or ``playwright``/``playwright-core``, +then the following options can be used: + +- ``GHCI_BROWSER_PUPPETEER_LAUNCH_OPTS``: JSON-formatted arguments to + be passed to `puppeteer.launch() + <https://pptr.dev/api/puppeteer.puppeteernode.launch>`__. +- ``GHCI_BROWSER_PLAYWRIGHT_BROWSER_TYPE``: one of + ``chromium``/``firefox``/``webkit``, the kind of browser to be + launched by ``playwright``. +- ``GHCI_BROWSER_PLAYWRIGHT_LAUNCH_OPTS``: optional, JSON-formatted + arguments to be passed to `browser.launch() + <https://playwright.dev/docs/api/class-browsertype#browser-type-launch>`__. + .. _wasm-jsffi: JavaScript FFI in the wasm backend -- GitLab