Manipulating the DOM with ReScript (Part 1)
J David Eisenberg
Posted on August 25, 2020
Sometimes you will want to write a single-page web application, but you’d like to manipulate the DOM directly rather than use a framework like React.
The project we’re going to build will ask for parameters to two equations based on trigonometric functions and then draw a polar or Lissajous figure from those equations.
Setting up
Start by creating a ReScript project, renaming it, and going to its directory:
git clone https://github.com/rescript-lang/new-project
mv new-project domgraphs
cd domgraphs
The src
directory contains two files: Demo.res
, the ReScript source file, and Demo.bs.js
the generated JavaScript. (The bs
stands for BuckleScript. BuckleScript has been rebranded as ReScript.) Remove the .bs.js
file, and rename the source file:
rm src/Demo.bs.js
mv src/Demo.res src/DomGraphs.res
Next, put the HTML into file src/index.html
.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>DOM Graphs</title>
<style type="text/css">
#canvas {
width: 450px;
float: left;
border: 1px solid black;
margin: 5px;
}
</style>
</head>
<body>
<h1>DOM Graphs</h1>
<canvas id="canvas" width="400" height="400">
Your browser does not support the <canvas> element :(
</canvas>
<div>
<p><input type="text" size="3" id="factor1"/>
<select id="fcn1">
<option value="sin">sin</option>
<option value="cos">cos</option>
</select>
(
<input type="text" size="3" id="theta1"/>
θ +
<input type="text" size="3" id="offset1"/>°
)</p>
<p><input type="text" size="3" id="factor2"/>
<select id="fcn2">
<option value="sin">sin</option>
<option value="cos">cos</option>
</select>
(
<input type="text" size="3" id="theta2"/>
θ +
<input type="text" size="3" id="offset2"/>°
)</p>
<p>
Type of graph:
<input type="radio" value="polar" name="graphType" id="polar"/>
<label for="polar">Polar</label>
<input type="radio" value="polar" name="graphType" id="lissajous"/>
<label for="lissajous">Lissajous</label>
</p>
<p><button id="draw" value="draw">Draw</button></p>
</div>
<script type="text/javascript" src="DomGraphs.bs.js"></script>
</body>
</html>
The <script>
element at the end gives the name of the JavaScript file containing the application code, which ReScript will generate from the DomGraphs.res
file.
ReScript includes a Dom
library for basic manipulation of the DOM, but for more power and convenience, you’ll want to use the bs-webapi
library. Put the dependency for bs-webapi
into the project’s bs-config.json
file:
"bs-dependencies": [
"bs-webapi"
],
Install bs-platform
and bs-webapi
:
npm install # installs the ReScript platform
npm install --save bs-webapi
Finally, we need to have a bundler that will take the HTML file and JavaScript generated by the compiler and put it in one nice web application. In this article, I’m using parcel
, because it works right out of the box and doesn’t require a lot of configuration. Install it globally so that you don’t need to duplicate it for every project.
npm install --global parcel-bundler
Accessing the DOM
Let’s take a look at some of the modules in bs-webapi
that you’ll use frequently, and those that we’ll use in this program.
Webapi
├── Canvas
│ ├── Webapi.Canvas.Canvas2d
├── Dom
│ ├── Webapi.Dom.Attr
│ ├── Webapi.Dom.ChildNode
│ ├── Webapi.Dom.Document
│ ├── Webapi.Dom.Element
│ ├── Webapi.Dom.Event
│ ├── Webapi.Dom.EventTarget
│ ├── Webapi.Dom.HtmlElement
│ ├── Webapi.Dom.HtmlInputElement
│ ├── Webapi.Dom.MouseEvent
│ ├── Webapi.Dom.Node
│ ├── Webapi.Dom.Text
│ └── Webapi.Dom.Window
Let’s do a quick test of the JavaScript Window.alert()
function. Replace the code in your DomGraphs.res
file with this code:
let testAlert = Webapi.Dom.Window.alert("It works!", Webapi.Dom.window)
The bs-webapi
library is set up so that, most of the time, the element you’re working with (in this case, the window we’re using for the alert) is the last argument in the call.
Compile and bundle:
npm run build # or: bsb -make-world
parcel build src/index.html --public-url ./
The parcel
command specifies the entry point for the application (src/index.html
) and the URL to use when serving the JavaScript—in this case, the same directory as the HTML (--public-url ./
). This will locally install the cssnano
package. You can specify the --no-minify
flag to prevent this local install.
When these steps are complete, you’ll see a file named DomGraphs.bs.js
, which is the JavaScript generated by ReScript, and a directory named dist
that contains the bundled web app.
$ ls dist
DomGraphs.bs.5acda38d.js DomGraphs.bs.5acda38d.js.map index.html
Every time you run parcel
, it generates a new number to append to the bundled files based on the content of the files being processed. To avoid getting multiple different .js
and .js.map
files accumulating in your dist
directory, you may want to remove the directory before rebuilding. Here is a bash
script to do exactly that:
#!/bin/bash
npm run build # or bsb -make-world
status=$?
if test $status -eq 0
then
rm -rf dist
parcel build src/index.html src/*csv --public-url ./
fi
If all has gone well, when you open the dist/index.html
file in your browser, you’ll see an alert telling you that It works!
Now that everything is set up, it’s time to start writing the project code.
Posted on August 25, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.