Reducing Flex compilation time with an assets module

Flex Published on February 28, 2010 by Andrea Bresolin Add comments

Example 1 (normal embeds):

Live demoSource code (LICENSE)

Example 2 (assets module):

Live demoSource code (LICENSE)

Some time ago one of my coworkers pointed me to a blog post that was giving suggestions to reduce the compilation time of a Flex project. Since we had long compilation times for our project at work, I decided to give it a try. The option that I chose was putting all the embeds inside a Flex module instead of embedding the assets directly inside each single source file. So, before testing the solution on the big project, I prepared a couple of small sample applications to test the difference and see if it was worth trying.

First of all, let’s briefly talk about the problem. Flex compiler can become slow if it has to embed a lot of assets in the application. This can be an issue if the application is particularly big. It seems that even if you change a single source file, the assets have to be embedded again to recompile everything. So, how can we avoid this? Using an assets module, and I’m going to call this module AssetsModule (quite straightforward).

In a standard application, when you want to embed an asset you have something like this:

<mx:Image source="@Embed(source='assets/myimage.png')"/>

With the usage of an assets module, you will have something like this:

<mx:Image source="{ModulesManager.getInstance().assets.myimage}"/>

To make our solution work, we need to make sure that there are no dependencies between the class that contains all the embeds in the module and the normal classes of the application. An interface is the right choice to achieve our goal.

Here are the fundamental components of our solution:

  • AssetsModule: the only purpose of this Flex module is to contain all the embedded assets of the application;
  • IAssetsModule: the interface that makes it possible to avoid dependencies between the application and the embedded assets;
  • ModulesManager: this manager class is responsible of loading the AssetsModule and providing access to it through the IAssetsModule interface.

The AssetsModule has a really simple structure. It’s just a collection of embedded assets. For every asset, a getter function is provided so it can be used in the application. We use getter functions instead of simple variables because we are implementing an interface, the IAssetsModule interface, so we must use functions.

<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
	implements="com.devahead.modules.IAssetsModule">

	<mx:Script>
		<![CDATA[
			[Embed(source="assets/myimage1.png")]
			protected var _myimage1: Class;
			public function get myimage1(): Class { return _myimage1 };

			[Embed(source="assets/myimage2.png")]
			protected var _myimage2: Class;
			public function get myimage2(): Class { return _myimage2 };
		]]>
	</mx:Script>

</mx:Module>

The IAssetsModule interface lists all the available assets through a getter function for each one of them.

package com.devahead.modules
{
	public interface IAssetsModule
	{
		function get myimage1(): Class;
		function get myimage2(): Class;
	}
}

Now it’s time to take a look at the ModulesManager class. Since the assets are shared across all the classes of the application, it’s a singleton. So we have a getInstance method that creates an instance of the modules manager, if it has not already been created, then loads the module. The application’s classes can access the assets through the assets instance property of the modules manager. That property can also be used in curly brackets because it’s bindable and an event (assetsModuleChanged) is dispatched as soon as the module has been fully loaded.

package com.devahead.modules
{
	import flash.events.Event;
	import flash.events.EventDispatcher;

	import mx.controls.Alert;
	import mx.events.ModuleEvent;
	import mx.modules.ModuleLoader;

	public class ModulesManager extends EventDispatcher
	{
		protected static var _instance: ModulesManager = null;

		public static function getInstance(): ModulesManager
		{
			if (_instance == null)
			{
				_instance = new ModulesManager();

				_instance.loadAssetsModule();
			}

			return _instance;
		}

		protected var _assets: IAssetsModule = null;

		[Bindable("assetsModuleChanged")]
		public function get assets(): IAssetsModule
		{
			return _assets;
		}

		protected var _assetsModuleLoader: ModuleLoader = null;

		protected function loadAssetsModule(): void
		{
			if (_assetsModuleLoader == null)
			{
				_assetsModuleLoader = new ModuleLoader();
				_assetsModuleLoader.addEventListener(ModuleEvent.READY, onAssetsModuleReady);
				_assetsModuleLoader.addEventListener(ModuleEvent.ERROR, onAssetsModuleError);
				_assetsModuleLoader.loadModule("com/devahead/modules/AssetsModule.swf");
			}
		}

		protected function onAssetsModuleReady(event: ModuleEvent): void
		{
			_assets = (_assetsModuleLoader.child as IAssetsModule);

			dispatchEvent(new Event("assetsModuleChanged"));
		}

		protected function onAssetsModuleError(event: ModuleEvent): void
		{
			Alert.show("Error while loading AssetsModule.\n\n" + event.errorText, "Error");
		}
	}
}

Now you might be curious about the compilation performance improvements that we get using this solution. To test it, I made a simple application in two different versions, one with the assets module and one with the standard embeds spread all over the application’s classes. In each version, the application is always made up of 100 components and each of them uses 100 images. The difference is how the images are used. I’m not going to write the example source code here since you can download it through the link provided at the beginning of this post and since it’s quite repetitive, instead here I’m going to give the different performance results that I got using the described technique.

Here are the performance results with the example application:

  With clean (m:ss) Without clean (m:ss)
Normal embeds 1:34 0:54
With AssetsModule 0:45 0:07

With clean means that the application has been built after cleaning the project in Eclipse (i.e. from scratch), while without clean means that I added only a space character in the main application mxml file and then built the project without cleaning it first. As you can see with the test projects, the difference is quite evident, especially when the AssetsModule doesn’t need to be rebuilt because we don’t need to clean the project. In that case, the assets don’t have to be embedded again and this allows to compile only the application’s classes.

Another important fact to note is that in the test project, the number of different embedded images is 100. With the normal embeds the same 100 images are embedded in each one of the 100 components used by the main file, while with the assets module, the 100 images are embedded only one time for all the different components. This means that with the AssetsModule we reduced the number of embeds from 1000 to 100 because we are reusing the same embedded asset across multiple application’s classes without needing to embed it again for each one of them.

At this point you could say: OK, it works great with the example application, but how does it work in a real world scenario? Since at the beginning of the post I wrote that I started looking into this subject because of the long compilation times we had for our project at work, I’ll show you some results that I got on that real project. It’s a big one (about 900 Flex source files, excluding external libraries). We use a few modules so the compilation times are still high also after refactoring it with the solution I described here, but let the numbers speak for themselves.

  With clean (m:ss) Without clean (m:ss)
Normal embeds 7:58 1:07
With AssetsModule 7:09 0:58

As you can see, we had an improvement, but the compilation time without cleaning the project wasn’t reduced much. This could be due to the project specific dependencies tree and complexity. Anyway, we had a reduction of compilation time with the clean. Note that with the AssetsModule the number of embeds became 280, while before the refactoring we had 977 embeds.

Now it’s time to talk about the conclusions. This is my opinion after trying all of this. Using an assets module is potentially very convenient to reduce the compilation time, but it depends on the specific project. When you’re compiling the project from scratch, the improvements should be noticeable. Anyway, using an AssetsModule is convenient also because you’re organizing well all the assets of you application, avoiding duplicate embeds and having a single central location for all of them. So, I would suggest to always use an assets module since the beginning to avoid potential compilation performance problems in the future. What seems sure is that you’ve got nothing to loose.

Tags: , ,

Leave a Reply

WP Theme & Icons by N.Design Studio
©2009-2010 Andrea Bresolin. All rights reserved. - Privacy Policy
Entries RSS Comments RSS