Haxe for javascript without global namespace pollution?
Asked Answered
L

4

9

This question only applies to Haxe version < 2.10

I've known about haxe for a while, but never really played with it until yesterday. Being curious, I decided to port showdown.js, a javascript port of markdown.pl, to haxe. This was pretty straightforward, and the javascript it generates seems to run fine (edit: If you want to see it in action, check it out here).

However, I noticed that the generated code dumps a ton of stuff in the global namespace... and what's worse, it does it by assigning values to undeclared identifiers without using the var keyword, so they're global even if you wrap the whole thing with a closure.

For example...

if(typeof js=='undefined') js = {}
...
Hash = function(p) { if( p === $_ ) return; {
...
EReg = function(r,opt) { if( r === $_ ) return; {
...

I managed to clean most of that up with sed, but I'm also bothered by stuff like this:

{
 String.prototype.__class__ = String;
 String.__name__ = ["String"];
 Array.prototype.__class__ = Array;
 Array.__name__ = ["Array"];
 Int = { __name__ : ["Int"]}
 Dynamic = { __name__ : ["Dynamic"]}
 Float = Number;
 Float.__name__ = ["Float"];
 Bool = { __ename__ : ["Bool"]}
 Class = { __name__ : ["Class"]}
 Enum = { }
 Void = { __ename__ : ["Void"]}
}
{
 Math.__name__ = ["Math"];
 Math.NaN = Number["NaN"];
 Math.NEGATIVE_INFINITY = Number["NEGATIVE_INFINITY"];
 Math.POSITIVE_INFINITY = Number["POSITIVE_INFINITY"];
 Math.isFinite = function(i) {
  return isFinite(i);
 }
 Math.isNaN = function(i) {
  return isNaN(i);
 }
}

This is some pretty unsavory javascript.


Questions

Is there a fork or clone of haxe somewhere that doesn't pollute globals? Is it worth it to modify the haxe source to get what I want, or has someone already solved this? Googling hasn't turned up much. I'm open to any suggestions. Meanwhile, I'm dying to see what kind of PHP code this thing's going to produce... :D


Answers?

Here are some of the ideas I've tried:

postprocessing

Here's my humble build script; it does a pretty good job of stripping stuff out, but it doesn't catch everything. I'm hesitant to remove the modifications to the built-in constructor prototypes; I'm sure that would break things. Fixing everything might be a bit of a task, and I don't want to start on it if someone's already done the work...

haxe -cp ~/Projects/wmd-new -main Markdown -js markdown.js

echo "this.Markdown=(function(){ var \$closure, Float;" > markdown.clean.js;

sed "s/^if(typeof js=='undefined') js = {}$/if(typeof js=='undefined') var js = {};/g ;
     s/^\([ \x09]*\)\([\$_a-zA-Z0-9]* = \({\|function\)\)/\1var \2/g ;
      /^[ \x09]*\(else \)\?null;$/d ;
     " markdown.js >> markdown.clean.js

echo "return Markdown}());" >> markdown.clean.js;

java -jar closure/compiler.jar --js markdown.clean.js \
--compilation_level SIMPLE_OPTIMIZATIONS \
> markdown.cc.js

--js-namespace switch saves the day

Thanks to Dean Burge for pointing out the namespace switch. This pretty much solved my problem, with a minor bit of help. Here's my current build script. I think this catches all the global variables...

NS=N\$

haxe -cp ~/Projects/wmd-new -main Markdown --js-namespace $NS -js markdown.js 

# export our function and declare some vars
echo "this.markdown=(function(){var \$_,\$Main,\$closure,\$estr,js,"$NS"" > markdown.clean.js;

# strip silly lines containing "null;" or "else null;"
sed "/^[ \x09]*\(else \)\?null;$/d ;" markdown.js >> markdown.clean.js

# finish the closure
echo "return "$NS".Markdown.makeHtml}());" >> markdown.clean.js;
Linkwork answered 30/9, 2010 at 6:52 Comment(3)
This question is no longer relevant since haxe 2.10. try try.haxe.org/#1cf90Particularism
@CésarAlforde Why is this question no longer relevant?Goodin
because since haxe 2.10 all the generated code is wrapped in an anonymous function, so there is not global namespace pollution, it's the same that you get from a coffeescript script.Particularism
M
7

I use the namespace switch on the compiler to clean those global root types up.

Madriene answered 30/9, 2010 at 9:17 Comment(2)
This took care of most of the stuff I was concerned about. There are still a few undeclared globals floating around; $_, $Main, $closure, $estr, js, and the user-defined namespace are the ones I've found. This can easily be fixed by declaring the vars at the beginning of the closure, thoughLinkwork
I have just found someone filed a bug for this: code.google.com/p/haxe/issues/detail?id=214Barter
P
3

Haxe is not meant to be used for writing an isolated reusable component in a javascript web application. This is evidenced by the fact that the compiler emits standard library for every goddamn compilation. Most optimal use of javascript target is to write an application entirely in haxe and call external stuff using untyped blocks hoping it won't break anything. You should treat haxe output like a flash clip, oblivious to the environment it runs in, assumes it is the only thing running.

Or you might try wrapping the code with a with() block.

Peripheral answered 30/9, 2010 at 8:13 Comment(3)
Thanks for the reply. If I'm not writing an isolated reusable component I'm writing garbage as far as I'm concerned. I still have a few ideas, though. BTW I LOL'd at the with block thing... I hope that was a joke :)Linkwork
BTW, haxetacy has a post-compiler that can split the classes into files: code.google.com/p/haxetacy/wiki/postcompilerBarter
I don't want to split them into files, I just want to avoid any globals that I didn't specifically export.Linkwork
J
2

there's a namespaced (experimental) haxe compiler here http://github.com/webr3/haxe

Junoesque answered 30/9, 2010 at 10:51 Comment(1)
Had a quick look but I'm not sure it's what I was after... Thanks though.Linkwork
H
1

The JSTM JavaScript generator macro optimizes haxe output in a number of ways:

  1. the javascript output is split into seperate files per type
  2. these files are optimized
  3. a loader script loads the required types asynchronously
  4. only one global variable is used: jstm
  5. only code that is actually required to run your app is downloaded
  6. new types can be loaded at runtime which makes possible highly scalable apps

check out http://code.google.com/p/jstm/ for more info.

Hanes answered 24/11, 2010 at 21:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.