Hello World project for hexMachina Find more information about hexMachina on hexmachina.org
- install Haxe minimum support Haxe 3.4
- download or clone git project
git clone https://github.com/DoclerLabs/hexMachina-HelloWorld.git
- in folder
cd hexMachina-HelloWorld
- install hexMachina framework with haxelib, locally in .haxelib folder
haxelib newrepo && haxelib install build/build.hxml
- Compile JavaScript target with HXML
haxe build/build-js.hxml
- Open index.html file in the bin folder to see the result of your build: 'Hello World'!
- Entry point -> Main
- DSL in xml file -> configuration/context.xml
- view for Javascript target -> js.HelloWorldView
- view for Neko target -> neko.HelloWorldView
- view for PHP target -> php.HelloWorldView
- view for Flash target -> flash.HelloWorldView
- module -> module.HelloWorldModule
The project can compile in Javascript, Flash, PHP and Neko targets.
# compile and run
haxe build/build-neko.hxml && neko bin/helloWorld.n
# compile and run on Mac or Linux
haxe build/build-php.hxml && php bin/helloWorld-php/index.php
# compile and run
haxe build/build-js.hxml && open bin/index.html
# compile and run
haxe build/build-flash.hxml && open bin/helloWorld.swf
var code = BasicStaticXmlCompiler.compile( new ApplicationAssembler(), "configuration/context.xml" );
When we compile the project, the XML file is converted in pure haxe code, and code
variable contains the applicationContext describe in XML.
At runtime, when we call code.execute();
, everything describe in DSL is executed (build objects, call methods, initialize modules...)
By default, HexMachina support two ways to describe DSL :
- XML, the one used in HelloWorld example; Xml DSL
- Flow, mimic haxe language syntax, Flow DSL The DSL describes configure of the application.
In Hello World example, DSL usage is limited to one view instantiation passe in the constructor of HelloWorldModule
. configuration/context.xml
DSL support conditional compiler, in this project is used to select which view class should be used by targets, based on Compiler Flag.
<view if="target-js" id="view" type="js.HelloWorldView" />
<view if="target-neko" id="view" type="neko.HelloWorldView"/>
<view if="target-php" id="view" type="php.HelloWorldView"/>
<view if="target-flash" id="view" type="flash.HelloWorldView"/>
If you look into build-js.hxml
, you will see :
-D target-js
-D target-neko=false
-D target-php=false
-D target-flash=false
When we compile the project with build-js.hxml
, view
will be an instance of js.HelloWorldView
, the other view will be ignored base on if
attribute value.
And the view
is passed as a constructor argument in HelloWorldModule
.
Let see the final result of XML convert in Haxe and compile to JavaScript :
<module id="module" type="module.HelloWorldModule">
<argument ref="view" />
</module>
<view if="target-js" id="view" type="js.HelloWorldView" />
<view if="target-neko" id="view" type="neko.HelloWorldView"/>
<view if="target-php" id="view" type="php.HelloWorldView"/>
<view if="target-flash" id="view" type="flash.HelloWorldView"/>
var view = new js_HelloWorldView();
coreFactory.register("view",view);
this.view = view;
var module1 = new module_HelloWorldModule(view);
coreFactory.register("module",module1);
this.module = module1;
hexMachina is organised around modules. A module could be seen as a micro-application, use to encapsulate our code, everything in the module is private. A module has is own domain, eventBus, controllers, models, injector, logger, not accessible outside themselves.
In HelloWorldModule
constructor, we map HelloWorldController
and HelloWorldModel
as Singleton
in the module injector.
With that configuration, each time we will require HelloWorldController
or HelloWorldModel
, we aks injector to return the instance map by key (IHelloWorldController
, IHelloWorldModel
), like this._injector.getInstance( IHelloWorldModel, '' )
. Instanciation will be done at the first getInstance
call.
Now, the model and the module controller are mapped, the next step is to link model and view (passed in the constructor from DSL). For that we will use hexMachina triggers (describe below).
public function new( view )
{
super();
this._map( IHelloWorldController, HelloWorldController, '', true );
this._map( IHelloWorldModel, HelloWorldModel, '', true );
this._get( IHelloWorldModel ).listeners.connect( view );
}
HelloWorldController only contains one method, uses to set message in the model.
As we can see, HelloWorldModel
instance can be got by injection, the one map in HelloWorldModule
constructor.
public function sayHello( who : String ) : Void
{
@Inject
var model : IHelloWorldModel;
model.setMessage( 'hello ' + who );
}
In our HelloWorld example the model, each time that setMessage
is called, we execute onMessage
on every listeners
connected by trigger (remember this._get( IHelloWorldModel ).listeners.connect( view )
in module constructor).
public var listeners ( default, never ) : ITrigger<IHelloWorldModelListener>;
public function new() {}
public function setMessage( message : String ) : Void
{
this.listeners.onMessage( message );
}
- bin/helloWorld.js is loaded in html;
Main.main
is called- then
code.execute()
does everything describe in DSL; - when everything is instancied,
module.initialize()
is called by DSL; - then
this._get( IHelloWorldController ).sayHello( 'world' );
is executed in the module; - then
model.setMessage( 'hello ' + who );
is executed in the controller; - then
this.listeners.onMessage( message );
is executed in the model; - and finally
onMessage
is called on target view.