1
0
mirror of https://codeberg.org/setop/elm-scripting synced 2025-11-08 21:49:57 +00:00

Compare commits

...

4 Commits

Author SHA1 Message Date
6050fb02a3 handle innerHTML 2025-10-05 01:35:45 +02:00
9566f305b5 more exploration 2025-10-02 19:08:12 +02:00
7025bc1104 refine backlog 2025-10-02 19:07:57 +02:00
a261077f6c support for debug mode 2025-10-02 19:06:58 +02:00
9 changed files with 87 additions and 5 deletions

View File

@@ -1 +1,2 @@
elm 0.19.1 elm 0.19.1
python 3.13.1-v2

View File

@@ -1,12 +1,21 @@
A tool to generate HTML code from Elm source in the terminal using [QuickJS](https://bellard.org/quickjs/). A tool to generate HTML code from Elm source in the terminal using [QuickJS](https://bellard.org/quickjs/).
# Requirements
* depends only on elm compiler, quickjs cli and a posix shell
* do not alter elm compiler
* do not alter quickjs cli
* do not patch elm compiler output
* provide acceptable performances (500ms for a big script)
# Design # Design
QuickJS (Qjs) is a [JavaScript runtime](https://en.wikipedia.org/wiki/List_of_JavaScript_engines), similar to V8 or SpiderMonkey, but lighter and faster. QuickJS (Qjs) is a [JavaScript runtime](https://en.wikipedia.org/wiki/List_of_JavaScript_engines), similar to V8 or SpiderMonkey, but lighter and faster.
As any runtime, Qjs can interpret JavaScript code, but it is not a web browser. It has no concept of an HTML document. As any runtime, Qjs can interpret JavaScript code, but it is not a web browser. It has no concept of an HTML document.
To bridge this gap, we add a minimal [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) implementation. To bridge this gap, we add a minimal [DOM](https://dom.spec.whatwg.org/) implementation.
Next, we concatenate this with the Elm JavaScript output and an app launcher snippet, then ask Qjs to interpret all of it. Next, we concatenate this with the Elm JavaScript output and an app launcher snippet, then ask Qjs to interpret all of it.
@@ -14,8 +23,10 @@ Next, we concatenate this with the Elm JavaScript output and an app launcher sni
* No event loop * No event loop
* Hence, no [TEA](https://guide.elm-lang.org/architecture/); the `main` function must return a static view * Hence, no [TEA](https://guide.elm-lang.org/architecture/); the `main` function must return a static view
* ~~The Elm app module must be called "Main"~~ * Hence, no Time, no Random, no Json Encoder/Decoder (!), no Http
* Nodes can only have one parent (this should always be the case) * Nodes can only have one parent (this should always be the case)
* Does not scale well : creating thousands of Nodes consumes a [lot of RAM](#Performances)
# Usage # Usage
@@ -39,6 +50,13 @@ Hello World!
</p> </p>
``` ```
## Performances
Acceptable for small scripts : 250ms on a modest x86_64 CPU and 64MB RAM for a 500 records into a table ; but is does not scale well as everything is loaded before processing ; no streaming contrary to the usual Unix way.
Generate 500k "li" loop took 17s and 900MB RAM.
# Prior Work # Prior Work
There are more complete tools for generating static sites with Elm: There are more complete tools for generating static sites with Elm:

28
TODO.md Normal file
View File

@@ -0,0 +1,28 @@
# Major
- find a way to process external data
- [ ] from stdout (use case : json)
- [ ] from files (use case : SSG)
- [ ] from http (use case : spider)
- implements some missing Web API:
- [Events](https://dom.spec.whatwg.org/#events)
- [Fetch](https://fetch.spec.whatwg.org/)(or [XMLHttpRequest](https://xhr.spec.whatwg.org/))
- [Promise](https://webidl.spec.whatwg.org/#a-new-promise) (if needed by the above)
- [ ] find a way to create a standalone executable (maybe with a combination of Google Closure Compiler and qjsc)
- [ ] find a way to stream instead of having the whole document in memory (output as soon as a node is created ? a child is added ?)
# Minor
- [ ] support for Elm debug (`-d`) mode (qjs does not implement `console.warn`, only `console.log`)
- [ ] in debug mode, keep the output
- [x] allow to specify or guess the main module name
- [x] if `innerHTML` attribute is set, output its value instead of the node tree
- [ ] allow to create standalone (`-s`) HTML document instead of fragment
- [ ] silence elm compiler message when successful
- [ ] skip compilation steps if source has not been modified ; run directly ; this mean keeping the output
- [ ] add proper copyright and license

18
build.debug.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/sh -eu
w1="$(mktemp out_$$_1_XXXX.js)"
elm make --output=${w1} $1 1>&2
sed -i -e 's!console.warn(!console.log(!g' ${w1}
w2="$(mktemp out_$$_XXXX.js)"
cat dom.js ${w1} launch.js > ${w2}
rm ${w1}
qjs --std ${w2}
# if qjs fails, output file will stay for debugging, else
rm ${w2}

View File

@@ -1,12 +1,14 @@
#!/bin/sh -eu #!/bin/sh -eu
CMDD=$(dirname $(realpath 0))
w1="$(mktemp out_$$_1_XXXX.js)" w1="$(mktemp out_$$_1_XXXX.js)"
elm make --optimize --output=${w1} $1 1>&2 elm make --optimize --output=${w1} $1 1>&2
w2="$(mktemp out_$$_XXXX.js)" w2="$(mktemp out_$$_XXXX.js)"
cat dom.js ${w1} launch.js > ${w2} cat ${CMDD}/dom.js ${CMDD}/preelm.js ${w1} ${CMDD}/postelm.js > ${w2}
rm ${w1} rm ${w1}

10
dom.js
View File

@@ -21,6 +21,10 @@ function Node(parent, tag) {
print(this.text); print(this.text);
return return
} }
if (this.innerHTML) {
print(this.innerHTML);
return
}
std.printf("<%s", this.tagName) std.printf("<%s", this.tagName)
// Set.difference(other) is not avalable in qjs // Set.difference(other) is not avalable in qjs
for (a of Object.keys(this)) { for (a of Object.keys(this)) {
@@ -53,6 +57,8 @@ document.getElementById = (_id) => { return target}
document.createElement = (tag) => new Node(null, tag); document.createElement = (tag) => new Node(null, tag);
document.createTextNode = (text) => { t = new Node(null, "#text" ); t.text = text; return t } document.createTextNode = (text) => { t = new Node(null, "#text" ); t.text = text; return t }
try {
// here will come the Elm app code // workaround for elm-explorations/markdown Markdown.toHtml
global = {};

6
preelm.js Normal file
View File

@@ -0,0 +1,6 @@
try {
// here will come the Elm app code

3
uloc.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/sh -eu
countuniq0 build.sh dom.js postelm.js preelm.js