Flash CS3 and _exclude.xml
Wednesday, March 26th, 2008While working on a modest Flash framework at HZDG, I ran into a problem that everybody who works on a modest Flash framework runs into: there's no easy way to prevent classes from being compiled into a SWF in Flash CS3. Back in the days of AS2, classes could be excluded from compilation by creating an xml file like the following:
<?xml version="1.0" encoding="utf-8"?>
<excludeAssets>
<asset name="MyClass" />
</excludeAssets>
Assuming that you had an FLA named "filename.fla," and saved the above xml as "filename_exclude.xml" in the same directory, the class MyClass would be excluded from your compiled SWF. This allowed you to create an application that used multiple SWF files without bloating the filesize and increasing the user's download time by including every class in every SWF. For some reason, however, this functionality was dropped in Flash CS3. Luckily, with the help of a tricky JSFL file, we can get it back.
Download the example and source files as a zip file or get them from my AS3 JSFL subversion repository. Then keep reading — I'll tell you what's going on.
Example
The example contains two FLA files: "library.fla" and "example.fla." The "library.fla" file contains only the following code on its first frame:
import PointlessThing;
var p:PointlessThing;
In practice, this FLA would be much more complicated, but I've simplified it for demonstration purposes. The only thing that matters is that one or more classes is imported and will be compiled into a swf. (The class I import — PointlessThing — is just that: it serves no real purpose other than to bloat the size of the SWF that it's compiled into so that we can be sure our _exclude file is working.) When we publish "library.fla," the resulting SWF is about 18k.
Our other FLA, "example.fla," is also very simple. It loads "library.swf" and, when the process is complete, creates a new PointlessThing and tells you how large the SWF file is:
import PointlessThing;
import flash.display.Loader;
import flash.system.LoaderContext;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
var ldr:Loader = new Loader();
var request:URLRequest = new URLRequest('library.swf');
ldr.contentLoaderInfo.addEventListener('complete', completeHandler);
ldr.load(request, new LoaderContext(false, ApplicationDomain.currentDomain));
function completeHandler(e):void
{
var p:PointlessThing = new PointlessThing();
textField.text = 'This SWF is ' + this.root.loaderInfo.bytesLoaded + ' bytes.';
}
Compiling this FLA results in a SWF that's approximately 21k. Most of that is because of our PointlessThing class (which of course is only a stand in for the many classes that these two FLAs might share in a real-world application). This added bloat, however, would be completely unnecessary if we could simply use the PointlessThing definition that's already been compiled into the "library.swf" file. In other words, we need to prevent PointlessThing from being compiled into "example.swf." We could use the bridge pattern, but then we'd have to create new interfaces and we still wouldn't be completely rid of those extra bytes.
Instead, we can use the "Publish (obey _exclude.xml).jsfl" file included in the download above. This allows us to actually prevent classes from being compiled into our SWF using a system that many Flash developers are already familiar with. The files you've downloaded already include the _exclude.xml file for our example:
<?xml version="1.0" encoding="utf-8"?>
<excludeAssets>
<asset name="PointlessThing" />
</excludeAssets>
In order for your _exclude.xml file to work, it must be named filename_exclude.xml (where filename is the name of your FLA) and saved in the same directory as the FLA.
This time, instead of publishing "example.fla" normally, run the jsfl file (Commands » Run Command…). Then open up the resulting SWF file — it should be about 3k, or less than 20% of the original!
Applications
This trick isn't just applicable to people creating Flash frameworks: virtually any project that loads external SWFs can benefit from eliminating redundant bytecode. And it's easy to fashion "Flash DLLs" that contain shared class definitions for runtime loading.
Though I chose to follow the _exclude.xml paradigm pioneered by previous versions of Flash, it doesn't really matter how the JSFL file determines which classes to exclude. In fact, having an _exclude.xml file for each FLA is almost certainly not an ideal situation. Because this technique is familiar to more developers than any other method of excluding classes, I figured it would provide a good starting point and allow for quick adaptation by users familiar with the process in AS2. Advanced developers, however, will probably benefit from picking apart the JSFL file and adapting it to suit their build process. All of my code is released under the MIT License so you can do whatever you want with it, but if you do wind up using it in Your Next Big Project, I'd appreciate a h/t.
