Learning Flex – Lesson 20, Creating Modular Applications

As your application gets larger, it could result in a pretty bulky swf that will take a long time to download and potentially cause users to get code for things they never use. There are also issues around re-using your code in different applications – if you just copy the source, it’s going to be a pain to maintain when you have bug fixes or enhancements for it.

Fortunately, there are ways to break up your code in Flex to reduce some of these issues.

Modules

Flex modules allow you to create a subset of code that can be loaded/removed at run time.  Say you’ve got an application that has features that only certain users have access to. You could provide the core of the app as your swf and then download the “special” functionality after a user of the correct type has logged in and asked to access that area. This saves everyone having to download code they may never  be able to access.

First of all you need to define your Module. The <mx:Module> tag defines the root of a module and you may have more than one of them in an application. It has a layout property that can be set to absolute, horizontal or vertical. More than likely, you’ll convert a current UI container class into a module so you can replace it’s tags with the Module ones.

FlexBuilder has functionality to aid with modules but if you’re using FlashDevelop, you’re going to have to do things a little differently. This post explains how to do that. Basically, you can specify compiler properties in an annotated comment (remember to do this within the <mx:Script> block if you’re Module is defined in MXML). The only addition I would make is to use the -source-path option to define the root of your source code so the compiler can find everything it needs to compile the module if you’ve got multiple folders within your source code.

The ModuleLoader class is a type of container that knows how to load and unload modules. As it’s a container, it can be added directly to the UI. It has a url attribute which specifies where to find the module swf at run time and can be given width and height attributes along with an id. The ready event is fired when the module is loaded and the object data of the module is available through the child property. The unloadModule() method can be used to remove the module.

A sample moduleLoader tag might look like this:

<mx:moduleLoader id="myModule" url="modules/myModule.swf" width="100%" height="100%" ready="handleModuleReady(event)"/>

In which case to set a property within my module I would cast the child to the module class to access the property like so:  MyModule(myModule.child).property=value;

You can also specify an error event handler to deal with problems trying to load your module. If you see an error something like this:

Error #1053: Illegal override of FlexModuleFactory in mx.core.FlexModuleFactory

Make sure you’re using the same  version of the Flex sdk for your module and your application (particularly if you’re using the FlashDevelop method covered above and you’ve got a project specific compiler specified – remember compiling the module with CTRL-F8 uses the default compiler).

Runtime Shared Libraries (RSL)

If you have common code that gets used between several of your applications, you can separate this out into a library and then either compile that in to each application or use it as an RSL. These can be cached on the client so it does not need to be downloaded every time the application is used.

It’s important to consider the size implications of using libraries – if you create ones that try to fit in too much, the overall size of your application at run time will go up as it will be including code from the shared library that it never uses.

Adobe has developed  special RSLs of the framework, data visualization and  data services classes so that they can be cached by the Flash player and any swf can use them, thus removing the need to compile in extra code and reduce the size of all apps. Thse special RSLs are digitally signed and have a .swz extension to ensure that only Adobe certified code is used.  They can be found in your SDK’s frameworks\rsls directory. Only Flash Player 9.0.115 and later can use the signed swz versions but there are swf versions available too.

To specify you wish to use  RSLs, you use the compiler -runtime-shared-library-path option. This is followed by the library file (swc) to compile against, the runtime location of the primary RSL (the swz), a policy file if needed (if this is your own unsigned RSL and you’re using it for a different domain) and the failover RSL (swf) runtime location for older Flash Players.

Here’s an example from my project:

-runtime-shared-library-path=C:\flex3sdk\frameworks\libs\framework.swc,framework_3.4.0.9271.swz,,framework_3.4.0.9271.swf

(I’m putting the framework RSLs in the same place as my application swf).

Creating a Flex Library

FlexBuilder has built in support for creating a Flex library (swc) file but for FlashDevelop you’ll need to use the command line compc compiler (there is a plugin for FlashDevelop but I couldn’t get it to work for me).

The best way to do this if you have several items is via a n xml configuration file.

You can then go to the bin directory under your SDK and run the command:

compc -load-config+=config-file.xml the += means in addition to the default config which makes sure you get access to relevant libraries.  Here’s an example configuration file:

<?xml version="1.0"?>
<flex-config xmlns="http://www.adobe.com/2006/flex-config">
  <output>C:\tools\flex\FlexGrocerLibrary\.\bin\FlexGrocerLibrary.swc</output>
  <use-network>true</use-network>
  <target-player>10</target-player>
  <warnings>true</warnings>
  <benchmark>false</benchmark>
  <compiler>
    <accessible>false</accessible>
    <allow-source-path-overlap>false</allow-source-path-overlap>
    <optimize>true</optimize>
    <strict>true</strict>
    <es>false</es>
    <show-actionscript-warnings>true</show-actionscript-warnings>
    <show-binding-warnings>true</show-binding-warnings>
    <show-unused-type-selector-warnings>true</show-unused-type-selector-warnings>
    <use-resource-bundle-metadata>true</use-resource-bundle-metadata>
    <verbose-stacktraces>false</verbose-stacktraces>
    <source-path>
      <path-element>c:\tools\flex\flexgrocerlibrary\src</path-element>
    </source-path>
    <external-library-path append="true">
      <path-element>C:\tools\flex_sdk_3.4\frameworks\libs\framework.swc</path-element>
      <path-element>C:\tools\flex_sdk_3.4\frameworks\libs\datavisualization.swc</path-element>
    </external-library-path>
  </compiler>
  <include-classes>
    <class>events.CategoryEvent</class>
    <class>events.ObjectDataEvent</class>
    <class>utils.Util</class>
    <class>valueObjects.Category</class>
    <class>views.MaxRestorePanel</class>
    <class>views.dashboard.ChartPod</class>
    <class>views.dashboard.ComparisonChart</class>
    <class>views.dashboard.SalesChart</class>
    <class>views.dashboard.TypeChart</class>
  </include-classes>
 <include-file>
    <name>downArrow.gif</name>
    <path>C:\tools\flex\FlexGrocerLibrary\src\assets\downArrow.gif</path>
</include-file>
<include-file>
    <name>upArrow.gif</name>
    <path>C:\tools\flex\FlexGrocerLibrary\src\assets\upArrow.gif</path>
</include-file>
 </flex-config>

Note the external library path entries for the framework libraries I’m referencing – the append attribute is to make sure these get added to any other libraries required. Make sure you specify these as external libraries rather than just libraries or they’ll get compiled in rather than just referenced.

Note also you can specify classes and asset files for inclusion.

Once this is run, you’ll have a swc file you can include as a library to your apps. To make it an RSL takes a little more work.  First of all, you need to extract the swf file from the swc using winzip or something similar, then you need to optimize it to remove debug information etc (you don’t need to do this if you’re building in your swc file as the compiler takes care of stripping that out when you generate a release build). You can find out how to optimize your RSL swf here.