22. JavaScript

Overview

Fantom provides support for compiling to JavaScript and running in JavaScript VMs such as web browsers. Most of the sys API is available, however not all pods and APIs are accessible due to limitations of the JavaScript VM environment.

Js Facet

You must explicitly mark types you intend to compile to JavaScript using the Js facet:

@Js
class GonnaBeJs
{
  Void sayHi() { Win.cur.alert("Hello!") }
}

Natives

To compile JavaScript natives, add the source directories to your build script using the jsDirs field. See Build Pod for an example.

TODO: flush out details

Deployment

The JavaScript compiler works by translating Fantom source code directly to JavaScript source code at compile time. This differs from the JVM/CLR, which work by using an intermediate format and translating to the target platform at runtime.

All Fantom source code in a pod marked as @Js will be compiled to a single JavaScript source file. This file will also include reflection information and other meta-data needed at runtime. The file is named <podname>.js and is packaged into the root directory of the pod file.

Running

You can run JavaScript compiled from Fantom by loading the pod's JavaScript source file into any JavaScript VM. There are no special requirements, other than loading the pods in the correct dependency order.

Testing

If you simply want to run your Tests from the command line, the Java runtime provides a built-in test framework using Rhino (requires Java 1.6+):

fan compilerJs::TestRunner

The test runner has the same semantics as the normal fant tool, but will load and execute your pod's source and tests in the Rhino scripting engine.

Browsers

Running Fantom JavaScript in the browser requires a bit more work. First you must expose the pods' JavaScript source files as URIs from your server. The simplest mechanism is to use FileWeblet:

file := `fan://$podName/${podName}.js`.get
if (!file.exists) { res.sendErr(404); return }
FileWeblet(file).onService

Then you must load the pods in the correct dependency order in your <head> tag. Finally, to "mount" the JavaScript runtime, invoke WebUtil.jsMain:

out.head
  out.title.w("My Page").titleEnd
  out.includeJs(`/pod/sys/sys.js`)
  out.includeJs(`/pod/concurrent/concurrent.js`)
  out.includeJs(`/pod/web/web.js`)
  out.includeJs(`/pod/gfx/gfx.js`)
  out.includeJs(`/pod/dom/dom.js`)
  out.includeJs(`/pod/fwt/fwt.js`)
  out.includeJs(`/pod/myPod/myPod.js`)
  WebUtil.jsMain(out, "myPod::Main")
  out.headEnd

A complete example is available in js-demo. Note that this example illustrates dynamically compiling code into the page. This is not required (or normal). The only requirement is to load your pods and invoke WebUtil.jsMain. There is also no requirement that fwt be used. You can simply run plain JavaScript, or interact with the DOM directly with the dom pod.

Running outside of Fantom

While running or serving Fantom JavaScript is easiest from a Fantom runtime, there is no requirement for that. You must first load the pods' JavaScript source into your VM (in order), or expose them from your web server using the pod zipfiles.

Once the pods have been loaded and interpreted by your VM or the browser's VM, you can launch any class using this syntax:

fan.<myPod>.<myType>.<method>

fan.myPod.MyType.staticMain();           // invoke a static method
fan.myPod.MyType.make().instanceMain();  // invoke method from instance