Slow Flex Builder compile and refresh solution - Modules
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.
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
2) Make a class that implements that interface and extends ModuleBase, also embed the graphics in there.
3) Create a module manager class
4) Set MyGraphics to be a module that gets built in your Project->Properties->Flex Modules settings.
5) Load your module somewhere at startup
6) Find the spot in your code that used that icon and replace it
So this:
Would become this:
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.
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.
NEVER import or otherwise use this class into your application. The goal is to keep it completely separate.
public class MyGraphics extends ModuleBase implements TimeLinerGraphicsModule
{
[Embed(source="/art/toolbars/add.png")]
protected var _addIcon:Class;
public function get addIcon() : Class { return _addIcon; }
...
}
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.
Labels: Actionscript, flex 3
6 Comments:
Great solution, well done Marc!
By
wenzi, At
11/07/2007 5:30 AM
Would creating a runtime CSS SWF accomplish the same thing as option 1? Why not use that method over creating a Module SWF?
By
Unknown, At
11/07/2007 6:13 AM
Hey, neat, look at that ... runtime css swfs. Learn something new everyday. :)
It certainly does look like it would cover option #1. We combined both options into a single module so we'll probably just leave ours but that does seem like an easier solution.
By
Marc, At
11/07/2007 6:25 AM
Also you may consider right clicking your flex project in Flex Builder 3 Beta 2 and choosing Properties > Flex Compiler. Then UNCHECK the box that says - "Copy non-embedded files to output directory". from my experience in FlexBuilder 3 beta 2 this drastically increased my compile time. It's just way too much to add every sub folder etc... when all you NEED is your embedded assets. I realize the module issue works but may also become tedious at times. Also Symbolic links to bin Directory works pretty good too for runtime assets. Anyways my 2 cents yo.
By
Frankie Loscavio, At
11/16/2007 12:19 PM
Try to put this arguments on Project->Properties->Flex Compiler options panel.
Where is: -locale en_US
Write: -locale en_US incremental=true -keep=true
It increases a little the building/compilling speed.
By
Anonymous, At
1/09/2008 5:29 AM
Embedded PNG:s slow down a lot, not other media to my experience. Flex apparently rewrites PNG:s somehow. Avoiding large png:s (using swf instead of them) is quite often a solution.
By
Juise, At
4/16/2008 5:15 AM
Post a Comment
Subscribe to Post Comments [Atom]
<< Home