COMMUNITY

Best way(s) to currently target Haxe code to Typescript/ES6 frameworks

es6
typescript
macro
haxe-js

(Marcelo Serpa) #1

As much as I’d love to only use pure-Haxe frameworks or existing externs/libs like the excellent haxe-react or tink libraries, sometimes it makes more business sense to leverage a framework that’s more popular/mainstream, like Ember and Ionic.

It’s been a bit of a pain for me to integrate/target Haxe with/to ES6/TS frameworks. Yes, you can go down an abstraction level and target ES5 but then:

  1. It requires a lot of code transformation through macros or a custom generator;
  2. You have to figure out existing abstractions at the TS/ES6 levels, such as decorators, figure out the ES5 output, and then make Haxe understand them (perhaps as meta-tags) and spit the right code;
  3. You often can’t leverage the build system of that framework (example: ember-cli processes ES6 code, Ionic's build system only supports TS natively). You then often have to re-implement most of the features of the said build system natively in Haxe through macros or a custom generator (as I mentioned in #1 and #2).

The only way to integrate at the TS/ES6 level at the moment, as far as I know, is to create a custom generator (i.e use and modify hxgenjs to generate code that can be parsed as TS, with support for the custom decorators translated from Haxe and such).

I’d love to use Haxe instead without needing to spend a huge amount of time re-implementing aspects of the framework I’m targetting. Because of time constraints and the friction added by the huge upfront time and energy investment of integrating Haxe with these frameworks, I’m often forced to just use the framework native language (TS or ES6) and skip Haxe altogether.

While it’d be awesome to have a native TS/ES6 target for Haxe (with first-class support for TS decorators for example), it’s not something that’s available at the moment, unfortunately. hxgenjs gives hope though, but is it the simplest way to solve this?

I’m looking for insights regarding this. Perhaps someone else smarter than me could shed some light on the issue? The solution could involve hxgenjs as well, but maybe there are other creative/simpler ways to solve this (the less friction, the better, think how easy it is to integrate ES5 libs with Haxe code through externs, something like this but targetting TS/ES6), or even some plan to have a native TS target? Any insights appreciated!

Thanks in advance!


(Dan Korostelev) #2

Hi! Our (and my personal) plan for Haxe 4.1 is to specifically look at the current JS generator and improve things that makes it too hard/impossible to use Haxe/JS output with modern ES6. So far the only real obstacle I found is ES6 classes. But clearly you know more, so I’d like to keep in touch regarding that! :slight_smile:

I will take a look at the issue with decorators, but it would be nice if you could present a minimal case that illustrates the issue.


(Marcelo Serpa) #3

Hi Dan, thanks for the prompt response!

Hi! Our (and my personal) plan for Haxe 4.1 is to specifically look at the current JS generator and improve things that makes it too hard/impossible to use Haxe/JS output with modern ES6. So far the only real obstacle I found is ES6 classes . But clearly you know more, so I’d like to keep in touch regarding that! :slight_smile:

Nice to know! Please keep it up! I think that in the end, the main goal is to make it easier to integrate Haxe with modern JS frameworks. At the moment, often more than not, it requires a lot of hacking, transformations and (forced) additional abstractions that don’t directly map to the ones in the native implementation. The more 1:1 mappings between Haxe<>ES6/TS we have, the better.

This would allow a more declarative way of describing the target framework to the Haxe compiler through externs (like we do for most of ES5 target code) and would (I hope) mainly retire the need for complex haxe abstraction libraries, like haxe-react, which albeit being excellent, has its own maintenance burden and needs to be playing catch-up with the native framework. This would leave the power of Haxe to create additional abstractions that add an edge / a plus over the native way of using the framework, instead of abstractions that are there just to support code generation, which end up being pure boilerplate.

In other words, I don’t want to spend time reverse engineering frameworks in order to use them from Haxe (as much fun as it can be to do it sometimes for learning purposes) I’d rather be able to tap into it as fast as possible and then use the power of Haxe to add to it as I see fit. Then Haxe would really add an edge instead of being a burden in the beginning.

I will take a look at the issue with decorators, but it would be nice if you could present a minimal case that illustrates the issue.

For one, Ionic heavily relies on Typescript decorators:

This is not very complicated to solve if you use the ES6 syntax code the decorators generate, it’s a bit hacky though. There’s some guidance for this here: http://nicholasjohnson.com/blog/how-to-do-everything-in-angular2-using-es6/.

Then, there’s the fact that Ionic (which is based off Angular 2), follows some conventions in the directory structure. For example, each Angular 2 “page” lives in src/app/pages/<name_of_the_page>/<name_of_the_page>.[__ts__, html, scss]. I did manage to hack hxgenjs to generate each hx class in the proper place as a js file, but it was very hacky.

I tried both ways, adding ES5-style code for decorators and trying to implement them directly in the js. Problem is that Ionic uses Angular 2 which uses WebPack under the cover, and WebPack does not recognize decorators when I use the .js extension (I setup tsconfig.json with allowJs: true so that my hxgenjs-generated js files could be taken into account by the TS compiler). However, if I go ahead and add the ts extension to make WebPack recognize the decorators, then I get all sorts of errors from the TS compiler, and hxgenjs cannot yet generate TS-compliant code. At this point, I gave up with the experiment and decided to go with vanilla TS.

I’m sure that with a bit more effort I could have made it work, and I might even look at it again at some point, but this initial friction was off-putting.

So I either need to tinker with the WebPack config to make it recognize the decorator syntax for js files, make hxgenjs generate the minimum code for the to satisfy the TS compiler or go fully vanilla ES5 for the decorators, which sometimes isn’t just very practical (but might be the simplest way to go other apart from not using Haxe).

Don’t get me wrong, I’m partially to blame here, but the initial effort was too great and I had to give up given the time constraints. Sometimes you just want to use Haxe as a better TS and tap into frameworks like Ionic, but at the present moment, it’s hard to take this minimalist route.

Here’s the source code for my (unfinished/WIP) experiment: https://github.com/fullofcaffeine/ionichxtest, install libs with yarn. The build process is twofold: there are two src folders and the hacked hxgenjs lives at the root of the project. Building the Haxe project will generate files in the src folder for Ionic. Then, yarn run start will build the Ionic project and serve it (currently shows an error about the unrecognized / unprocessed @Component decorator). Let me know if you have more questions about it.

Thanks.


(Dan Korostelev) #4

alright, that’s not a minimal case that i could really look into :slight_smile: I briefly looked at TS decorator documentation and it seems to be the same thing as python decorators, basically just functions that receive class/field ant return a potentionally modified one, tho it’s mentioned as experimental and subject to change, so I don’t know. but it shouldn’t be hard to support. i’ll research on that a bit more.

regarding modular output. we came to conclusion that it’s impossible to satisfy requirements of every js framework, so the current plan is to implement generation of a js file per haxe module, which should be easy enough to post-process and repack to meet the needs of whatever framework.