Modular flash applications with haxe 2.07

The power of --gen-hx-classes

Imagine a core application that contains some GUI elements and other stuff of general purpose. A build.hxml would look like this:

-swf bin/core.swf
-main Main
--gen-hx-classes

This creates the usual hxclasses headers along with the .swf output file itself, so your folder structure would look like this:
myproject
    bin
        core.swf
    hxclasses
    src

Imagine further you want to create a "module" or a "plugin", i.e. something that doesn't run on its own, but is rather executed within a core application. You want your plugin to use elements, say GUI elements, of the core. The usual approach is to -swf-lib the core in order to gain access to them, so your module's build.hxml could look like this:
-swf bin/modules/module.swf
-main ModuleMain
-swf-lib bin/core.swf

This will work, but has the downside of actually including all necessary classes and thus potentially big GUI graphic elements in your module output .swf, making it, in effect, not really a module at all.

Let's try a different build.hxml setup:

-swf bin/modules/module.swf
-main ModuleMain
-cp hxclasses

The only difference is the additional classpath to hxclasses instead of the -swf-lib linkage. You now get fully typed access to all classes of the core application (again), but their implementations are not included in your module output.

Runtime linking

Running your .swf now will not work because the Flash Player cannot find the implementations of the externally declared core classes. The idea here is to run the core.swf instead and load the module.swf into its ApplicationDomain, which will provide the implementations of all classes the module needs. A sample module loader could look like this:

public function loadModule(moduleName:String):Void
{
    var loader = new Loader();
    var ctx = new LoaderContext();
    ctx.applicationDomain = ApplicationDomain.currentDomain;

    loader.load(new URLRequest("modules/" +moduleName+ ".swf"), ctx);

    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e)
    {
        // here you can init your module
    });
}

Within the closure, you can initialize your module. For example, you could by convention instantiate a moduleName.Api class, passing some central information to its constructor:
var t = Type.resolveClass(moduleName +".Api");
Type.createInstance(t, [myApi]);

Modules using modules?


This works as well, you simply have to add the --gen-hx-classes to the build.hxml of a module and add the generated hxclasses to the classpath of another module. However, you might want to organize your modules in different directories since the haxe compiler will always generate headers in hxclasses, which could possibly cause overwriting issues.

Pro and contra


+ compiling your modules will be fast because the compiler doesn't have to check huge .swf library files
+ the module's output files are small
+ you rarely have to recompile the core
+ (almost) everything is typesafe
+ it's quickly set up

- you must make sure your core application contains everything the modules need, which can potentially lead to subtle bugs
- you cannot use --dead-code-elimination on the core
- at present, you cannot use macros in your modules because the neko macro environment gets confused by the flash-bound hxclasses

version #9550, modified 2011-01-22 10:36:07 by Simn