No exclude.xml in Flash CS3 for AS3: Solution via Bridge Pattern

Exclude.xml, functionality in Flash 8 and MX 2004 that allowed you to exclude ActionScript 2 classes compiled into your SWF, does not work in Flash CS3 for ActionScript 3. A similar function is available in Flex 2 via the load-externs option. This is the basis of how Flex modules work. The lack of this functionality just adds another challenge to Flash Developers who have expectations coming from AS2; this actually makes AS3 usage in Flash worse than AS2 when creating Flash sites, or large Flash applications.

“Great Jesse, no one cares about your vendetta, so how do we fix it?”

I have no clue, but the server architect I work with, John Howard, had a good idea. We’ll probably implement it in the next 2 weeks after we hit some interim milestones. I’ll explain his idea at the bottom, but first a review. If you want to skip the review, go to the bottom.

Why Exclude Classes?

When creating large Flash websites or applications, you’ll tend to have many SWF’s. This was especially true with AS2 driven not just from a media perspective, but also from a performance one. If you go to a visual website, say Flickr, and spend 20 minutes on it, you’ll probably download hundreds of images. Rather than download 20 minutes worth of images initially, you download on the fly and download whats needed. Flash and Flex apps can be built this way; it’s called excluding classes in Flash, and modules in Flex.

In Flash, the main way to download assets over time is to load external SWF’s into another SWF. You use the loadMovie/loadMovieNum functions or the MovieClipLoader class, or the Loader component to do this pre-AS3. Although you can load images and video externally from a SWF just like a webpage can, the SWF format itself has visual advantages, such as images that can have alpha channels, yet also have JPEG compression applied to those images. JPEG does not have alpha channels, GIF only has a 1 bit alpha, and PNG never got the glorious browser support we all desired and only has lossless compression. When creating visual layouts that have a lot of media such as a multitude of images, audio, and/or video meshed with animations, this can be a stand alone SWF. Typically those types of things would be put into their own symbols such as a Graphic or MovieClip. However, if they got large enough, you should make it an external SWF for 3 reasons.

The first is because it’s faster for you to make changes to the SWF. When you do a test movie, aka compile a SWF, Flash has to render animations, compress your bitmaps and sounds, as well as integrate your video if any. This can take a lot of time. Sometimes that time isn’t actually that bad, but because of the frequency in which you are re-compiling your SWF’s to check for visual accuracy, and doing this say every 2 minutes, and you end up saving 2 seconds in your compile… well, hey, that’s almost 10 minutes of your day you just saved right there! This is more apparent for larger media, however, like mp3 compressing a bunch of audio, or integrated video that can make your FLA’s take a minute or more to compile.

The second is you can get help, aka RAD development. Instead of sharing the same FLA, you can have a project broken up into multiple FLA’s that another designer/developer can use so you both can work together on the same project.

The third is that you only make the user download what they need to download. If you have a site that has 6 sections, you only need to make the user download the first section. You can either load the other section when the user clicks to go there, or download in the background once the first is done.

The work-flow for visual projects in Flash is dead easy. There are a lot of frameworks, such as Gaia, and methodologies out there for facilitating this kind of work.

For Flex, you have to be a rocket scientist. Flex 3 has some help in this department, but they are a long way off in how easy this is in Flash.

For Flash applications, it’s a little different. In the beginning, our first enhancement to this was Remote Shared Libraries. What this allowed you to do was have a “reference MovieClip”, or any other symbol for that matter, in your library. Your symbol would have the SWF that it is stored in stored with the symbol as metadata. You’d go make that Symbol in another FLA, and upload those SWF’s together to your website. When your SWF was played, if a remotely shared symbol appeared on the time line, the Flash Player would automatically go download this for you.

The bad was you really didn’t have much in the way of code in control or getting events about this. However, that ended up saving you a lot of work since it did it for you. Either way, this worked out pretty good because you could treat the symbols as normal symbols; the FLA would actually keep a local copy. You could update the symbol from the Library in case it changed in another FLA. You could additionally ensure every time you compiled it updated for you, but this was the slowest thing on the planet.

In the end, Remote Shared Libraries were a management nightmare in Flash. For simple projects where you had a master SWF, they worked damn good. For anything more complicated, it was what I call “Flash Jenga” (Jenga is a game consisting of a tower of stacked wooden blacks the size of your pinky. The challenge was to remove bottom blocks without making the whole thing topple). If you got it to work, you were the shit, but it was very easy to break, and once it did, things came crashing down. The tools never really helped you manage your Remote Shared Libraries.

Flex Builder has some nice improvements in this realm with regards to tool support.

The biggest problem, however, with Remote Shared Libraries in regards to application development and code. Like I said, they still work good for assets; anything that isn’t ActionScript classes.

Since ActionScript 2 and 3 utilize a lot of classes, and thus have dependencies, this makes things challenging when creating your applications for low initial download impact in mind. I’ll rehash my version here, but reading these 3 blog posts by one of the the mxmlc compiler creators, Roger Gonzalez formerly of Adobe, is probably a little more authoritative and better written. (Multi-SWF Applications, Modular Applications (part 1), Modular Applications (part 2)).

It’s hard enough to architect an application, especially when accounting for a designers needs for dynamic Views. It’s another when you visualize a package of classes, and then have to account on how to reduce dependencies so you only load some classes in some SWF’s, and others in another SWF, but be sure not to use in a master SWF, thus reducing the overall file size. This can lead to code duplication, or a non-efficient use of a RSL, or too much in an RSL that’s not used by 80% of the application. As if software development wasn’t hard enough, you have a designer who keeps changing your MovieClip instance names.

You could just say fuggit, and just load a bunch of SWF’s as users navigate to those sections. However, your wasting bandwidth by using duplicated code. For example, in the image below, 3 forms are loaded into a master SWF on the fly whenever a user navigates to that section. Each other has it’s own unique set of components; however, each also has it’s own copy of Button, or mx.controls.Button to be exact in AS2. Say that your Button is 14k. You’ve now duplicated that 14k across 3 SWF’s.

Exclude-01

…however, why not just load that class once, and have all other SWF’s use that same already loaded class? You can! First, a review on how AS1/AS2 classes work.

In the old AVM, aka, the one that runs AS2 and A1 (regardless of player version), classes are defined on _global. The _global keyword is like this object that never dies, and is accessible via the _global keyword in ActionScript. It’s also accessible across SWF’s and across _levels (_level is like a loaded SWF basically). This means that SWF’s loaded in can access classes on _global as well as defining their own. They cannot, however, overwrite classes. In AS3, this behavior is controlled via ApplicationDomain; in AS2, it is what it is.

Since you know you’ll be loading those 3 SWF’s into a SWF that will already have the Button class defined, you can then just not compile those 3 SWF’s with the Button class. The user then only has to download 14k once; any other SWF that uses the Button class can use that already downloaded class. In the example below, the Button class has been moved to the shell.swf, increasing it’s size from 8k to 22k. However, notice that that same 14k is now removed from the login.swf, the amount.swf, and settings.swf.

Exclude-02

In this particular example, you’ve ended up saving 24k! Now, imagine a large website or large application consisting of dozens of SWF’s that could potentially use the same class. You can see how this feature saves a ton of bandwidth.

How Exclude.xml Works

Exclude.xml works like dis. If you have a FLA called “my.fla”, you create an XML file in the same directory next to the FLA called “my_exclude.xml”. When you compile your FLA, Flash will look for that exclude.xml file. If it finds it, it’ll read it. Any class written in that XML file will NOT be compiled into your SWF. The con to this is the SWF no longer works on it’s own; you have to load it into another SWF to test. The plus is that you’ve now saved file-size since the SWF will get the class it needs to work from another main.swf. Most importantly, your work flow has changed; just your SWF.

In the past, I wrote some JSFL to automate this. One JSFL script would delete the exclude.xml file, and then do a test movie. You map this JSFL to Control + Enter so your Test Movie works as normal. I then created another JSFL script to create the exclude.xml based off of a set of classes I knew would be shared throughout the site, and then test your movie. I then mapped this JSFL to Control + Alt + Enter, replacing test scene. That way, you can create SWF’s ready for deployment easily.

Now that Flash CS3 has E4X, writing such scripts is a ton easier, and gives ANT in Eclipse a run for it’s money in automation. Course one could use Rake (Ruby‘s version of Make), but anyway.

In Flex using mxmlc, this part is actually automated for you; the XML you need is generated via the mxmlc -link-report parameter. You immediately feed that generated XML file to -load-externs, and booya, you have a SWF with those classes removed.

So, pretty pimp, huh? Guess what; it doesn’t work in Flash CS3 for AS3. I know, right? “Yeah hi, I’ll take some AS3 with a side of lame sauce.”

Using mxmlc Doesn’t Work

I tried using mxmlc with -incremental set to true, making sure it doesn’t actually recompile the entire SWF, but just those classes that have changed. If you make sure your FLA has a Document class, this’ll work; mxmlc can use that as the root class. However, in recompiling your classes, it basically ignores the symbols your FLA has created, thus “I’ll take it from here” attitude. Um…mxmlc, dude, f-off, at least we can use pixel fonts…

You could do this in MTASC for AS2, I guess their bytecode replacement techniques are just different. Either that, or I’m maybe missing a mixture of mxmlc compiler arguments… :: crosses fingers hoping someone says so in comments ::

Bridge Pattern to the Rescue (sort of)

So, my boss suggested a proxy technique. Basically, we use the J2EE blah blah blah official blah blah Bridge Pattern. The Bridge Pattern in a nutshell is 2 classes that implement the same interface; one provides the pretty face, whilst the other does all the work. The pretty face is called the Abstraction and the one who does the work is called the Implementation.

If you were going to create a Button component using the Bridge Pattern, you would do it in 3 steps.

  1. Create the IButton interface
  2. Create the Button class that implements IButton
  3. Create the ButtonImpl class that implements IButton, and does all the work.

Flex 2 actually uses this in a few places, specifically the ToolTipManager class. ToolTipManager merely proxies everything to ToolTipManagerImpl. He instantiates an Implementation class (ToolTipManagerImpl) via a magic string to ensure there are no dependencies, meaning the compiler doesn’t know to compile it in. To ensure it is compiled in, however, they do do (gross) a dependency variable above that.

This is how the Bridge pattern will work to save file size. The child SWF’s will only contain the interfaces and abstractions; the implementations will be in the main SWF. First thing to do is create the interface, mainly for typing purposes.

Now that that’s done, I do the same thing the ToolTipManager does; I instantiate the ButtonImpl class inside of Button via a magic string. This ensures that Flash doesn’t see the usage of the class. If it did that, Flash would compile it in. A magic string, however, cloaks it from the compiler. Using flash.utils.getDefinitionByName, I can instantiate the ButtonImpl class with my magic string:

var btnImpl:Object = getDefinitionByName("com.multicast.controls.ButtonImpl");
impl = new btnIpml() as IButton;

Now, I can just create my sets of components as normal:

var btn:Button = new Button();
addChild(btn);

However, the ButtonImpl class won’t be compiled into the child SWF’s. Instead, he’ll be compiled into the main shell.swf.

Based on some initial tests, I reckon interface will run about 500 bytes to 2k, and the Button class from 2k to 4k. The Impl will be around 8k. So, being conservative and rounding up, all of my child SWF’s will no longer have 14k in them, but rather 6k. Like exclude, the developer whether using Flex Builder with an ActionScript project, or Flash CS3, can code normally with AS3’s strong-typing, and/or Flash’s time line and symbols. The down-side is I’m still duplicating anywhere from 2k to 6k in any additional child SWF that uses Button.

It’s not perfect, but it’ll do.

Unknowns

What I haven’t figured out yet is the implementation details. Premature optimization is the root of all evil so I hear, but seriously, how much speed does keeping the interface for strong-typing really give me? What if I just remove the interface, and cast impl in the example above as a DisplayObject, or more accurately, a MovieClip? I feel the Interface is for Java people who like a bunch of classes; to me, 2 is too many, let alone 2 and an interface. I’m only doing this because a feature that worked in 2 previous Flash IDE’s now doesn’t; don’t punish me by making me write more classes to compensate for a feature that removed classes in the first place. Convention works for the Ruby guys; why not me? I don’t really want to spend much time on benchmarks, but any dynamic look up will cause the old AVM to be used, and since this component set is created with AS3, it kind of defeats the purpose of using AS3 if you aren’t going to take advantage of the runtime speed.

Secondly, what is impl, a DisplayObject, or rather a class that uses a DisplayObject via Composition? Traditional programmers who came to Flash in the past would use Composition all the time because the thought of extending a GUI base class freaked them out. So, instead of extending MovieClip or Sprite, they’d instead store a reference to the MovieClip or Sprite passed in the constructor. All methods would then act on that reference, as opposed to the class itself via Inheritance. Would doing Composition be better? Although it may have a tad more code, it’d be redundant, so hopefully zlib SWF compression would see that and I’d still hit my small file size goal. Furthermore, I wouldn’t end up with twice as many DisplayObjects. In AS2 that was bad, but in AS3… not so much. If all Buttons were just a simple shell with the “real” Button inside it as the impl, is that really that bad? My gut says make the Implementation class via Composition to save on the number of DisplayObjects.

Basically, rather than doing:

// Button.as
private var impl:IButton;

public function Button():void
{
        var btnImplClass:Object = getClassByDefinition("com.multicast.controls.ButtonImpl");
        impl = new btnImplClass() as IButton;
        addChild(impl);
}

public function setSize(w:Number, h:Number):void
{
        impl.setSize(w, h);
}

// ButtonImpl.as
public function setSize(w:Number, h:Number):void
{
        this.width         = w;
        this.height     = h;
}

I’d instead do:

// Button.as
private var impl:IButton;

public function Button():void
{
        var btnImplClass:Object = getClassByDefinition("com.multicast.controls.ButtonImpl");
        impl = new btnImplClass(this) as IButton;
}

public function setSize(w:Number, h:Number):void
{
        impl.setSize(w, h);
}

// ButtonImpl.as
private var btn:IButton;

public function ButtonImpl(ref:IButton):void
{
        btn = ref;
}

public function setSize(w:Number, h:Number):void
{
        btn.width         = w;
        btn.height        = h;
}

Any other ideas (or corrections), lemme know.

17 Replies to “No exclude.xml in Flash CS3 for AS3: Solution via Bridge Pattern”

  1. Wow, great summary and commentary. I figured the PopUp manager implementation class was just in there for pattern/organizational purposes but I can see how this would be a great method of reducing compile times and swf sizes. Your solution looks promising but I do hope that Adobe is coming up with a better solution, even though Flex 3 seems a step in the right direction. I don’t know much about Thermo but based on circumstantial evidence I have a feeling it must fit in the gap between the designer and the developer and I hope provides a means of compiling efficiently for Flash projects. We’ll have to wait till next week to see. Anyway thanks for the tips and keep up the great research. I’ll try one of your patterns if I get a chance over the nest few weeks and get back.

    – paul

  2. Thanks for the tip! I really can’t believe Adobe “excluded” this previously documented feature from Flash CS3. We’ve developed several VERY large products for a VERY large user base over the past few years using a framework and workflow that depends on exclude files for all the benefits you mentioned.

    The first thing I noticed when I started migrating our code from AS2 to AS3 was that our run-time loaded modules were MUCH larger. Obviously, the exclude files were being ignored and the chain of imports caused the entire framework and every utility class to be compiled into every swf. I found a couple notes about exclude files in the latest documentation, and one post stating that support for exclude files MIGHT be released in an update to Flash CS3. UNBELIEVABLE!

    So, I started searching for a solution. I’d come to the conclusion that I could use getDefinition and type everything as Object. Your solution sounds much better. On the other hand, I wonder if anyone at Adobe would like to provide a better solution or promise a patch within the next 6 months.

  3. There’s unfortunately a lot of things missing in flash 9 cs3. Including removing about 7 different necessary components and web service functionality, etc. On top of this, there is nothing really new in flash 9 cs3 that is earth shattering, except for the export to quicktime functionality (which doesnt work very well) and actionscript 3.0.

    It looks like a very rushed product in my opinion to meet the CS3 release schedule.

    Where’s all the cool stuff adobe?

  4. I found another solution that involves the usage of the flex swc compiler ‘compc’ and the flex compiler ‘mxmlc’. You use compc to generate an swc and mxmlc to generate the accompanying library. Flash CS3 will compile intrinsic against that swc!, so the only thing you need to do is load your ‘dll’ before you execute anything else that involves the usage of your library classes.

    For examples and more information, read more here:
    http://labs.qi-ideas.com/2007/12/25/using-flex-compiled-code-within-flash

  5. Thanks,
    This post gives insight into modules and shell. And how to use the swf files efficiently. I found that Flash CS 3 has a component for Flex. Using this we can directly generate .swc files from Flash CS 3. The only problem I am facing currently is loading swc files at runtime. Please if you have any suggestions about using RSL’s i.e. swc at runtime.

    Thanks

  6. I have been searching for solution to exclude class using flash 9 IDE, but realised _exclude is removed. I then used flex library projects to create code library and use it in flash, I took the advantage of refering other library projects as library path to do the type checking of clases which I dont want to include. Things works fine till I realised that the file size of exported swc form flex is much larger than flash exported swc. I created one single class without any composition or inheritance and compiled both from flash and from flex libray projects, the flash exported file size is 11k where as flex exported swc size is 20k. Does anybody know what extra goes into flex swc? I plan to use flex as a code compiler to take the advantage of excluding classes. Does anybodu know any other solution?

  7. Just as some insight into why things are the way they are:

    You have to understand that the Flex compiler and Flash compiler only share the core AS3 compiler, and this is a pretty hairy prospect as it is, given that one version is C++ and one version is Java. The .FLA format is actually some sort of terse serialization of the in-memory structures of the C++ app, so supporting that in Flex is pretty much infeasible.

    So, the question was that given that, we’d previously (Royale/Flex 1.0) gone down the path of shrugging and giving up on more than bare minimum compatibility. For Flex 2, we decided that although pure 100% source interoperability was still too hard to tackle, the best approach was to interoperate well at the SWC level. Thus, everything in Flex (and to a lesser degree, in Flash Authoring) is oriented around slinging around baskets of definitions in SWC format.

    I shared many of your concerns you express here, which is why I created -link-report and -exclude and -load-externs and the Modules system (particularly the AS3 API, not the flimsy MXML-friendly facade).

    Basically, until I did that, there was no solution in either product. I got a lot of grief for adding it to Flex because it highlighted its omission in Flash, but I stand by my decision to at least provide the option somewhere.

    I’m a bit of an odd duck, though as typical Flex/Flash developers go, though. I just build my own stuff on top of SimpleApplication and use Flash to build pretty assets. If they’re pure media, I embed them. If they have some code attached (which I try to avoid) I link them as SWCs. I make heavy use of modules and interfaces, and other than cross-site issues and some annoyances with embedded fonts, life is grand. :-)

  8. Oh, and manotosh, just crack open your SWC and look inside to see what dependencies got dragged in.

    Incidentally, just because the SWC is big, doesn’t mean that an application compiled from that SWC will also be big. Library projects include everything referenced by every definition in the library. Applications that reference libraries exclude anything that isn’t a transitive dependency.

    Excluding stuff for which there are actual hard references is dangerous. It is much better to try to sever extra dependencies, most cleanly by using interfaces.

Comments are closed.