If you are working with HaxeNME, you might have noticed that compiled JS/HTML5 applications do not necessary work same as other platforms. Or don't work at all. Or don't compile because of some uncommon unimplemented method that you've used.
Reasons of such behaviour are even somewhat understandable - process of recreating Flash API on JavaScript+HTML5 isn't exactly an easy task, especially since multiple features do not exist in both of two in the same way or do not exist in second at all, meaning that implementation may require a trick or two to work.
And as code base is accumulating "tricks" by multiple contributors, it does not necessarily remain entirely stable.
For example, if you've decided to clear your BitmapData-based 640x480 buffer via BitmapData.fillRect, you are making a huge mistake - the function is not just doing this pixel-by-pixel, but also via ImageData API.
Overall, this article is dedicated to substituting Browser/Jeash part of NME by your own library in JS compilation.
Preparations
Unlike what you may have thought, possibility of replacing standard library upon compiling to JavaScript is included in NME, and exists for a number of versions.
First thing that has to be done is exclusion of NME library for JS/HTML5 target. This is fairly straightforward, being replacement of one line in application.nmml from
<haxelib name="nme" />
to<haxelib name="nme" unless="html5" />
Though this isn't the only step. "NME builder" program is made in such way, that if your code attempts to import any NME class, an NME preloader will be used as a startup node. Which, in turn, will lead to an error, since it was just excluded from project library set. Thus you have to also get rid of NME imports for start, minimizing your Main.hx to something like this for a working case:
package ; class Main { public function new() { trace("Oh, hi."); } static function main() { new Main(); } }
This way it will successfully compile and run across multiple platforms as it would before. With one exception - now, if you would inspect the JS file, you would not find any NME code in it. Or any other code, generally, except your minimalistic Main class and a couple of methods used by Reflect.
Implementation
Sure, the code works well when there's no code (citation needed), but application has to work somehow, and specifically NME code must work on non-JS targets, while JS target code should not leak into other platforms.
Fortunately, there are preprocessor directives in Haxe, thus the code can be limited to a structure of this kind:
#if js // JS(+HTML5) implementation #else // NME implementation #end
For unification of interface used in such "splitter" classes, either typedefs or class implementation should be used, so that a class picked by compiler would contain used methods and properties on all platforms (worth mentioning that such approach is also used in NME itself). For example, for implementation of buffer/texture in JS you would need to make a class that would wrap a HTML5 Canvas, while NME implementation would need either a BitmapData or BitmapData+Sprite/Shape combination.
This approach allows to have smaller and faster output, which can be especially meaningful for mobile applications (where standard Jeash "cascade" drawing itself is already too pricey performance-wise).
Main flaws of these approach are need of implementing classes itself (takes time) and need for custom resource and data loader (takes a macro, which also takes time).
Attached example demonstrates implementation of aforementioned approach on a relatively simple class for drawing via Canvas and BitmapData accordingly, which works identically in both JS and NME on output.
Download ZIP
(FlashDevelop project)