#905 Auto reloading fan code

kaushik Sun 10 Jan 2010

When using wisp, Is there a way to modify some fan code and have it reloaded without restarting the server?

I saw some discussions on using sys.compile to do this, but wasn't able to get exactly how it's done. Can somebody give me a clearer example. 
For eg., Iam using the eclipse plugin and have the following code in WebHello.fan.

In the example below, once the start the server once, How do I get it print "hello world #5" without restarting the server?

class WebHello : AbstractMain {

@opt="http port"
Int port := 8080

override Int run()
{
  wisp := WispService
  {
    it.port = this.port
    it.root = HelloMod()
  }
  return runServices([wisp])
}

}

const class HelloMod : WebMod {

override Void onGet()
{
  res.headers["Content-Type"] = "text/plain; charset=utf-8"
  res.out.print("hello world #4")
}

}

brian Sun 10 Jan 2010

We used to have that built into the webapp stuff, but don't have a WebMod off hand which will do it. But it pretty easy to create a mod which loads a script which defines a Weblet using sys::Sys.compile. Something like this:

const class ScriptMod : WebMod
{    
  override Void onGet()
  {
    weblet := (Weblet)Sys.compile(scriptFile).make
    weblet.onGet
  }
}

kaushik Sun 10 Jan 2010

Thanks Brian. Amazing.

Now on to next step, Say I've another helper class as below

class Helper
{
   Str hello(){
   return "hello"
   }
}

If I am trying to reference Helper in my weblet like this

Helper helper := Sys.compile(File(`fan/Helper.fan`)).make

I get Unknown type Helper for local declaration. delcaring pod::Helper does not seem to work either. I was able to get it work using

Obj helper := Sys.compile(File(`fan/Helper.fan`)).make
res.out.print(helper->hello)

Is there any better way of doing this? Or atleast set a flag somehow like

devMode := true
and then do a Sys.compile(...) if devMode is true, otherwise do a Helper.make()?

brian Sun 10 Jan 2010

As of right now you can't share type definitions between scripts.

Couple options:

  1. put your type definitions in a proper pod and import via using
  2. just use -> and do everything dynamically
  3. use an existing type in a pod such as Weblet

kaushik Tue 12 Jan 2010

Thanks brian. In all the 3 options above, I've to change my code just for reloading it dynamically.

What about the possibility of this?

In the same example above, If I put the Weblet and Helper in the same ".fan" file like this...

const class MyMod : Weblet
{
  override Void onGet()
  {
    res.out.print(Helper().hello)
  }
}
class Helper{
  Str hello(){
    return "You don't need to compile to run!"
  }
}

and then compile this file and invoke the onGet, everything works fine. I assume that its because both Helper and MyMod will then be loaded into the same namespace...

So my question is, can't we have a

Sys.compileAll(file1, file2...)

or better

Sys.compilePod('podName')

So that all files given will be recompiled(if changed) loaded in to the same namespace? That way i don't have to change any code for auto reloading new classes.

I don't want to be sounding persistent or anything about this, but auto reloading is an Amazing Productivity feature while developing web apps. And to me, the productivity difference is almost as good as using a language like fan over java

brian Tue 12 Jan 2010

There is a ticket to change pods to be identified with a Uri #720. That feature will allow you to import other script files into your namespace (all back with the auto reloaded infrastructure).

That feature is still pretty high on the priority queue, so it might make it into the next build.

Login or Signup to reply.