Search code examples
node.jsfay

Require fay code from nodejs


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?


Solution

  • 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.)