Marc Hughes


Home
Blog
Twitter
LinkedIn
GitHub
about
I am a developer from a bit west of Boston.

Slow Flex Builder compile and refresh solution - Modules

04 Nov 2007

For the past month I've been plagued with up to three minute compile times on Flex Builder 3 Beta 2. I've also been plagued with long several minute waits of "Refresing bin/".

Last week I solved the issue for one of my projects and prevented it from happening to another.

Apparently embedding graphics causes a performance hit in compiling, refreshing directories, and even just before launching. So if you have a hundred or so of these:

<mx:Button icon="@Embed(...)" />

You'll be in a world of pain. The easiest solution is to move those embed calls into your style sheet and then compile your style sheet as a module.

Here's how to make a style sheet module:

1) Create a new MXML module (file->new->flex->MXML module)
2) Add your stylesheet reference to that.


<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" width="0" height="0"
creationComplete="trace('iconsloaded')">
<mx:Style source="style.css" />
</mx:Module>

3) Next, remove the reference to your style sheet from your main application.
4) Now, in your main MXML or AS file add some code to load your module.


protected var styleLoader:ModuleLoader;
protected function init() : void
{
styleLoader = new ModuleLoader();
styleLoader.addEventListener(ModuleEvent.READY, onModuleLoad );
styleLoader.addEventListener(ModuleEvent.ERROR, onModuleError );
styleLoader.url = "IconsModule.swf";
styleLoader.loadModule();
}
protected function onModuleLoad( e:ModuleEvent ) : void
{
maximize();
var mainApp:MainApplication = new MainApplication();
mainApp.percentHeight = 100;
mainApp.percentWidth = 100;
addChild(mainApp);
}

protected function onModuleError(e : ModuleEvent ) : void
{
Alert.show("Could not load module IconsModule.swf","Error",Alert.OK );
}

You can see there that I intialize my main application component after the module has loaded. I didn't have to do this in a Flex app, but in my AIR app that component wouldn't get all of the new styles if created before the module was loaded.

Option 2

Sometimes, it wasn't practical for me to put the embedded graphic in a stylesheet. In those cases I:

1) Made an interface listing all the embedded graphics

public interface MyGraphicsModule
{
// Bindable tags are there purely to suppress warnings,
// these properties never change after startup.
[Bindable(event="moduleChanged")] function get addIcon() : Class;
...
}

2) Make a class that implements that interface and extends ModuleBase, also embed the graphics in there.

public class MyGraphics extends ModuleBase implements TimeLinerGraphicsModule
{
[Embed(source="/art/toolbars/add.png")]
protected var _addIcon:Class;
public function get addIcon() : Class { return _addIcon; }

...
}
NEVER import or otherwise use this class into your application. The goal is to keep it completely separate.

3) Create a module manager class

public class MyModules
{
[Bindable] public static var graphics:MyGraphicsModule;
}


4) Set MyGraphics to be a module that gets built in your Project->Properties->Flex Modules settings.

5) Load your module somewhere at startup

public function loadModules() : void
{
graphicsModuleLoader = new ModuleLoader();
graphicsModuleLoader.addEventListener(ModuleEvent.READY, onModuleLoaded );
graphicsModuleLoader.addEventListener(ModuleEvent.ERROR, onModuleLoadFailure );
graphicsModuleLoader.url = "MyGraphics.swf";
graphicsModuleLoader.loadModule();
}

protected function onModuleLoaded( event:ModuleEvent ) : void
{
if( event.target == graphicsModuleLoader )
{
var o:Object = event.module.factory.create();
MyModules.graphics = event.module.factory.create() as MyGraphicsModule;
}
}

6) Find the spot in your code that used that icon and replace it

So this:

[Embed(source="/art/icons/addIcon.png")]
public var addIcon:Class;


Would become this:

public var addIcon:Class = MyModules.graphics.addIcon;


This all seems like a pretty tedius job to do, but I ended up writing a perl script to scour the source tree, find all the references, and replace them for me. Unfortunately I did that script as part of my day-job and can't share it with everyone right now. I'll ask for permission on Monday.

The end result was we went from a 3.5 minute wait from saving a code change to executing the application to a 20 second wait. Not too shabby considering the size of the codebase we have.