Example exposing Haxe classes for JavaScript

So you want to write a library so others can use you code? Sure that is possible in Haxe... easily!

The code used in this example can be found here.

How to start

Create a folder named foobar (please use a better name; any name will do) and create folders bin and src. See example below:

+ foobar
    + bin
    + src
        - Main.hx
    - build.hxml

The Main.hx

I am not going to write something difficult here, you eventually will. But it will inform you about how to share you code.

class MyClass
{
    var name:String;

    function new(name:String) {
        this.name = name;
    }

    public function foo() {
        return 'Greetings from $name!';
    }
}

Biggest change in this class from previous examples: there is no entry point

static public function main() : Void {
    var main = new Main();
}

Create a hxml file

# build.hxml
-cp src
-js bin/MyClass.js
MyClass

And again there is no entry point: -main Main.

Are you not sure how to build the Haxe file into JavaScript, check this

When we export this class to JavaScript it will be transpiled into:

// Generated by Haxe 3.4.0
(function () { "use strict";
var MyClass = function(name) {
    this.name = name;
};
MyClass.prototype = {
    foo: function() {
        return "Greetings from " + this.name + "!";
    }
};
})();

See, no way to access that code. This is great, because you don't want your code influencing other javascript libraries by accident.

But what if you want other scripts to use your code?


To fix that we add @:expose to the class.

@:expose
class MyClass
{
    var name:String;

    function new(name:String) {
        this.name = name;
    }

    public function foo() {
        return 'Greetings from $name!';
    }
}

We look at the generated JavaScript code again:

// Generated by Haxe 3.4.4
(function ($hx_exports) { "use strict";
var MyClass = $hx_exports["MyClass"] = function(name) {
    this.name = name;
};
MyClass.prototype = {
    foo: function() {
        return "Greetings from " + this.name + "!";
    }
};
})(typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this);

Huh?

Let's add it to a html page, like you normally would. And let's see how we access this script:

<html>
    <head>
        <title>Haxe JS - expose</title>

        <!-- Your Haxe compiled script -->
        <script type="text/javascript" src="MyClass.js"></script>

        <script type="text/javascript">
            // JavaScript code
            var instance = new MyClass('Mark');
            console.log(instance.foo()); // logs a message in the console
        </script>
    </head>
<body>
</body>
</html>

Yes, in your browsers console log you will find the correct line: Greetings from Mark!


Not convinced? Remove the @:expose to the class, rebuild the JavaScript and test it in the browser with previous mentioned html.

You will get:

Uncaught ReferenceError: MyClass is not defined(anonymous function) @ index.html:12

Nice?

Controle over package and or clasname

Sometimes you want more controle over package-/classname, this is possible by using @:native("GiveItAnotherName").

I made an example in code folder.

To make it more obsious what I mean, I put the class in the /utils/-folder

package utils;

@:native("GiveItAnotherName")
@:expose
class MyUtil
{
    var name:String;

    public function new(name:String) {
        this.name = name;
    }

    public function foo() {
        return 'Utils class "GiveItAnotherName" : $name!';
    }
}

Use this for the build.hxml:

-cp src
-js bin/util.js
utils.MyUtil

This will create a file bin/util.js (no package, different name)

// Generated by Haxe 3.4.4
(function ($hx_exports) { "use strict";
var GiveItAnotherName = $hx_exports["GiveItAnotherName"] = function(name) {
    this.name = name;
};
GiveItAnotherName.prototype = {
    foo: function() {
        return "Utils class \"GiveItAnotherName\" : " + this.name + "!";
    }
};
})(typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this);

To test this, just add <script type="text/javascript" src="util.js"></script> to the index.html file

Now you have a couple ways to access your code:

Native JavaScript (check bin/index.html):

// JavaScript code
var instance2 = new GiveItAnotherName('Matthijs for plain JavaScript');
console.log(instance2.foo()); // logs a message in the console

But we still can use the code in Haxe, but with the original package and class-name:

var instance3 = new utils.MyUtil('Rick from Haxe code');
trace(instance3.foo()); // logs a message in the console

If you would not use @:native the call would be

var instance2 = new utils_MyUtil('Matthijs for plain JavaScript');
console.log(instance2.foo()); // logs a message in the console

Because JavaScript doesn't have packages. You might find it ugly, so this way you have more controle over the output;

The Haxe build file, build.hxml

There are a lot of different arguments that you are able to pass to the Haxe compiler. These arguments can also be placed into a text file of one per line with the extension hxml. This file can then be passed directly to the Haxe compiler as a build script.

-cp src
-js bin/MyClass.js
MyClass

Build js with Haxe

To finish and see what we have, build the file and see the result

  1. Open your terminal
  2. cd to the correct folder where you have saved the build.hxml
  3. type haxe build.hxml
  4. press enter

You could build everything directly in the terminal.

haxe -cp src -main Main -js bin/example.js -dce full

It will have the same result

results matching ""

    No results matching ""