-
Notifications
You must be signed in to change notification settings - Fork 11
GHC JS browser introduction blog post/tutorial #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
e5aef39
WIP blog post & associated example code for GHC JS browser example
JoshMeredith e8624e2
WIP browser example blog post - building ghc and start of node/browse…
JoshMeredith ccbd4e7
Browser example blog post
JoshMeredith 031eedc
Browser example blog post intro/conclusion
JoshMeredith d3d4e51
Browser example: incorporate feedback
JoshMeredith 8027fcd
Browser example: incorporate feedback 2
JoshMeredith 69d0b35
miscellaneous wordsmithing
34a523e
add code explanation
2bdd961
more wordsmithing
edfce60
Update blog/ghc-js-browser-example/browser-example.md
JoshMeredith 35268e9
Update browser-example.md
JoshMeredith f99717a
Browser example: screenshot and other small changes
JoshMeredith 15f1a0a
Browser example: typo
JoshMeredith 6777696
Update blog/2023-01-18-javascript-browser-tutorial.md
JoshMeredith 01a3554
Update 2023-01-18-javascript-browser-tutorial.md
JoshMeredith cfcec31
Update 2023-01-18-javascript-browser-tutorial.md
JoshMeredith 1d24d15
Update 2023-01-18-javascript-browser-tutorial.md
JoshMeredith 571344e
Set docasaurus static directory
JoshMeredith 49d1f42
fix en-dashes, remove passive voices
8d6ac89
Update 2023-01-18-javascript-browser-tutorial.md
JoshMeredith 2a8a8a0
Update blog/2023-01-18-javascript-browser-tutorial.md
hsyl20 97373b1
Update blog/2023-01-18-javascript-browser-tutorial.md
hsyl20 524bcb0
Update blog/2023-01-18-javascript-browser-tutorial.md
hsyl20 444ca9b
Update blog/2023-01-18-javascript-browser-tutorial.md
hsyl20 f6bcd1e
Update 2023-01-18-javascript-browser-tutorial.md
JoshMeredith 0db79fd
Update 2023-01-18-javascript-browser-tutorial.md
JoshMeredith 1a560c1
Update blog/2023-01-18-javascript-browser-tutorial.md
hsyl20 8dd58a9
Update and rename 2023-01-18-javascript-browser-tutorial.md to 2023-0…
hsyl20 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
|
||
# GHC JavaScript Browser Example | ||
|
||
## Introduction | ||
hsyl20 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
## Building | ||
|
||
TODO: Can we do something with the cabal project file and/or environment variables and the with-compiler/with-hs-pkg fields to optionally specify /path/to/build/stage1/bin in the case that the user is currently building the compiler themselves, since Hadrian can't install stage 1 and prebuilt binaries are generally unavailable. | ||
|
||
## Features | ||
|
||
### Foreign Import JavaScript | ||
|
||
To access JavaScript-specific features in Haskell, we can import them via Haskell's `foreign import` syntax. | ||
|
||
In our example (in `app/Main.hs`), we have: | ||
``` | ||
foreign import javascript unsafe "((html) => { return setInner(html); })" | ||
setInnerHtml :: CString -> IO () | ||
``` | ||
|
||
Here, there are a number of details to take note of: | ||
- we specify the import as a string of JavaScript with _a single function call_ (TODO: Elaborate on syntax) | ||
- _TODO: Explain unsafe vs interruptible_ | ||
hsyl20 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- we must pass arguments as types from the `base` library's `Foreign.C` module - in this case `CString` | ||
- return types must also be `Foreign.C` types, or unit (`()`) | ||
|
||
On the JavaScript side (in `js/example.js`), we have: | ||
JoshMeredith marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
function setInner(html) { | ||
document.body.innerHTML = "example" + h$decodeUtf8z(html,0); | ||
return; | ||
} | ||
``` | ||
|
||
In this JavaScript function, we match the inputs specified in the `foreign import` declaration. However, we unfortunately have to currently use internal functions of GHC's JavaScript backend - in order to convert this `CString` (stored as a byte array) into a JavaScript string, we use `h$decodeUtf8z`. | ||
|
||
## Current Limitations | ||
hsyl20 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
### Libraries Using C FFI Imports | ||
|
||
If a function is imported via `foreign import ccall`, then that symbol will end up being referenced in the generated JavaScript, with `h$` prepended. | ||
|
||
In the example code, the `lucid-svg` library indirectly calls `bytestring`'s `cIsValidUtf8`, which imports the c symbol `bytestring_is_valid_utf8`. To work around this, we can add the missing definition in our own javascript - which we do in `js/example.js`: | ||
|
||
``` | ||
function h$bytestring_is_valid_utf8(bs) { | ||
return true; | ||
} | ||
``` | ||
|
||
Although this definiton is far from ideal, it demonstrates that we can link in missing library c functions via our own implementation in our project. | ||
|
||
JoshMeredith marked this conversation as resolved.
Show resolved
Hide resolved
|
||
### TODO: Talk about the ghc-options JS source linking workaround? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{-# LANGUAGE OverloadedStrings #-} | ||
|
||
module Main where | ||
|
||
import Foreign.C.String | ||
import Lucid.Svg | ||
|
||
|
||
foreign import javascript unsafe "((html) => { return setInner(html); })" | ||
setInnerHtml :: CString -> IO () | ||
|
||
|
||
svg :: Svg () -> Svg () | ||
svg content = do | ||
doctype_ | ||
with (svg11_ content) [width_ "300", height_ "200"] | ||
|
||
|
||
image :: Svg () | ||
image = rect_ [width_ "100%", height_ "100%", fill_ "red"] | ||
|
||
|
||
main :: IO () | ||
main = do | ||
setInnerHtml =<< newCString (show $ svg image) | ||
print $ svg image |
13 changes: 13 additions & 0 deletions
13
blog/ghc-js-browser-example/browser-example/browser-example.cabal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
cabal-version: 2.4 | ||
name: browser-example | ||
version: 0.1.0.0 | ||
|
||
executable browser-example | ||
main-is: Main.hs | ||
|
||
build-depends: base ^>=4.17.0.0, | ||
lucid-svg, | ||
text, | ||
hs-source-dirs: app | ||
ghc-options: js/example.js | ||
default-language: Haskell2010 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
|
||
function h$bytestring_is_valid_utf8(bs) { | ||
return true; | ||
} | ||
|
||
function setInner(html) { | ||
document.body.innerHTML = "example" + h$decodeUtf8z(html,0); | ||
return; | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.