4

Is it possible to require fay-compiled modules from other simple javascript files on the server side in nodejs? That would be just great. Maybe there is some option in compiler to produce commonjs-compatible modules?

AlexMost
  • 104
  • 7

2 Answers2

1

It's possible to use fay code from javascript, but at the moment it's a bit verbose, you need to use fully qualified names and manually force function calls.

var m = new Main();
document.body.innerHTML = "The 10th fibonacci number is : " + m._(m.Main$fibN(9));

Everything is flat inside Main at the moment, we'd want to separate the compilation of each module so each can be output separately. (then we can also migrate to haskell-packages)

Then we need the possibility to output a wrapper that does forcing and type conversions for each module so you don't need to this manually when called from JavaScript.

Here are some related tickets: #279, 260

Adam Bergmark
  • 7,316
  • 3
  • 20
  • 23
  • Thanks for your reply. For now i have a lot of code that is written in coffeescript and executes in node.js environment on the server. Due to the lack of good type checking system and other haskell advantages i'd like to try to rewrite some separate modules in faylang. And for now i don't know how to interact with those modules from my old code. How can i export this Main function? – AlexMost Jun 23 '13 at 18:30
  • Everything exported by the Main module in your Fay source is exported when you instantiate the module. `var m = new Main(); m._(m.main)` should to the trick – Adam Bergmark Jun 24 '13 at 18:42
  • nodejs doesn't really let that kind of global scope pollution fly -- the module fay compiles basically ends up being file-scoped, which is kind of useless to include. – muhmuhten Jul 20 '13 at 01:32
  • Ah yes, of course. The new module generation is pretty much complete over at https://github.com/faylang/fay/tree/modules so a --node flag or similar should be added that will generate export statements for all modules. – Adam Bergmark Jul 21 '13 at 14:36
1

This is probably a bad idea, since it depends quite a bit on peculiarities of fay's generated code.

Note the following points:

  • Regardless of the name of the compiled module, fay instantiates into the variable main.
  • Under node.js, the return value from require is the module's modules.export (which initially is the same object as export -- but it doesn't necessarily stay that way).
  • A variable can be used before its scoping is declared with var. The variable referenced is the same. Its cares nothing for its source ordering, and everything for what has happened at runtime.
  • Fay by default (i.e. without --library) can instantiate an object and execute main.

Notably, this means that we can, within main, modify module.exports or exports to export the fay code. Of course, we must use the ffi, but it's a rather simple affair; the following, compiled without --library (which, yes, is mildly counterintuitive, and really does lend credence to the hypothesis that this is a nasty hack, doesn't it) work to some extent:

import FFI

main :: Fay ()
main = ffi "module.exports = main"

when require'd from node, the returned object is something to the effect of

{ 'Main$main': 
   { forced: true,
     value: { value: [Circular] } },
  _: [Function: Fay$$_],
  '$': [Function: Fay$$$],
  '$fayToJs': [Function: Fay$$fayToJs],
  '$jsToFay': [Function: Fay$$jsToFay] }

With a working knowledge of Fay's internal representations, it is then possible (though perhaps too much effort) to write a javascript wrapper for all the thunk-forcing and such.

(We could do more -- in fact, with a bit more ffi work, we could write all the bindings as ffi code. It would be mildly silly, though.)

muhmuhten
  • 3,313
  • 1
  • 20
  • 26
  • clever :) Writing a wrapper is some work, but it shouldn't be too hard with the new code generator. With a flag the compiler can generate strict modules for each Fay module that does forces and transcoding appropriately. – Adam Bergmark Jul 21 '13 at 14:40