While 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.


Comments

Gravatar Ronald

Hi Matt, this is great! I've spend half a day scouring through the net trying to find some hints of how this can be done in Flash CS3 IDE. It really solves my problem of not being able to use Flex (so no -load-externs) and the lack of time to spend on development and research on other methods such as the bridge pattern and other obscure "rumors" such as this. Really appreciate it.

One thing to note though. This method doesn't work if you're using Document class – all the codes has to be in the MainTimeLine.

Gravatar matthew

Hm.. I might be misunderstanding you, but if you're saying that the JSFL file won't work if the code is in a document class, I think you're mistaken. I've tested it with a document class and it works perfectly.. which makes sense: the JSFL file doesn't actually analyze the FLA at all, so it doesn't care if the classes you're excluding are used on the timeline, in the document class, in the library, or not used at all.

Gravatar Ronald

Hi mattew, I did a bit more testing… basically, the compiler script doesn't work if I'm using "auto declare stage instance" and referencing a stage instance from within the document class. It works if I disable that and manually declare each stage instance I use in my document class. It isn't a major thing, just a catcha that people need to be aware of.

I'll send you a reconstruction of your example with a document class that doesn't work. Really great work none the less.

Gravatar matthew

Ah, I see. The script was erroring because the class was accessing the stage instance as a property. For various reasons, I never do this (in fact, I think allowing this was a mistake on Adobe's part — I may write an article explaining why in the future), but the practice is pretty much standard for Flash developers so it certainly can't be allowed to break the script! (The script also needs better error handling but that's a matter for another day.)

Anyway, I've updated the JSFL and the problem should be fixed. Thanks for bringing this to my attention!

Gravatar Siu Lun .Net » Blog Archive » Flash CS3 and _exclude.xml

[...] ways to use shared library between swf files in Flex, but not in Flash IDE. That is, until I found this amazing piece of work done by Matthew Tretter. Which basically brought _exclude back into Flash [...]

Gravatar Ihsan

This rocks!

Without this, I solved the problem via using a proxy extension class instance casted to object which can store references in a hidden static object (array) and grab it from the applicationDomain so no compile time checking which means trouble.

Now I have compile time checking. And no more surfing on the bla bla net org forum telling nothing…
I have spent 3 days for that… Finally someone who knows what he is doing…

Thank you very very much.

Gravatar Ihsan

I made a change for the temporary library since I import not only .as class files.
If you import an .as file containing only a public object declaration or a public function instead of a public class, the object or function reference will give type error when declared as follows;
var _n: (a function reference); or
var _n: (an object reference, actually a variable);

So I changed the line in your script
as += 'import ' + excludedClasses[i] + ';\nvar _' + i + ':' + excludedClasses[i].split('.').pop() + ';\n';
into
as += 'import ' + excludedClasses[i] + ';\nvar _' + i + '=' + excludedClasses[i].split('.').pop() + ';\n';

which equates or assigns the public symbol declaration in the .as file (regardless of whatever it is)…
Since ;
var _n=(a function reference); or
var _n=(an object reference, actually a variable); or
var _n=(a class reference);
assignments will always work.
I tested it and it is working. I do not know if it has any drawbacks.

I hope my contribution may help all of us.
And again,

Thank you very very much for your script.

Gravatar matthew

Hey Ihsan.. I think that line can actually be simplified even further. If I'm not mistaken,

as += 'import ' + excludedClasses[i] + ';\n' + excludedClasses[i].split('.').pop() + ';\n';

should do the trick. I'll update the script as soon as I get a chance. Thanks for your input!

Gravatar Ihsan

Hi Matthew,

You are wellcome,

Tested the last version, works perfectly, a masterpiece. Less code, same result. Thank you.

BTW, that line is reaching to its satori, nirvana … whatever :)

Gravatar matthew

One more step on the way to nirvana:

as += 'import ' + excludedClasses[i] + ';\n(' + excludedClasses[i].split('.').pop() + ');\n';

By adding the parenthesis, we avoid the compiler warning. I've updated the zip and repository with this version.

Gravatar Guillermo

I'm trying to figure out a way to add a Document Class to my .fla with JSFL. I hope that makes sense.

So I have a JSFL that creates a .fla with some functionality in it. then it gets saved as .fla.
Manually I'm going to publish this file but I would like the .fla to have the document class in there already adding it from my JSFL.

any ideas how to do this.

document class in the properties for Flash 9. This .fla will be flash 9 as3.

any ideas would be greatly appreciated.

thanks.

Gravatar matthew

@Guillermo: Use document.docClass. This info is covered in the "Extending Flash" section of Flash's help.

Gravatar laan

you are so great! with that, we can distribute flash application to multi-module.

Gravatar GUTTERSHARK » Flash 9 CS3 Exclude Classes.

[...] so much to Matthew Tretter for putting this together, and figuring out how to get exclude classes support in Flash 9. I have an update that [...]

Gravatar aaron smith

Hey Matthew,

Thanks so much for finding this. There was 1 problem that I found. It would not work with global class paths that were set in Flash preferences. I fixed your script, and fixed all of the file path/search logic. Check it out here: http://blog.guttershark.net/?p=25

Gravatar Jason MacDonald

I've tried running this example a dozen times and every time the PointlessThing.as gets included into the Library.swf. No idea how I could be doing something wrong, but I see the script generate all the temp swc's and fla's then delete them and generate the final Library.swf, but every time the excluded files are included anyway. The library file always end up being 19/k. No errors are ever generated.

I'm on Vista and wondering if there's something weird going on.

Gravatar Jason MacDonald

Why is it you always figure out the answer yourself right after posting the question?

Anyways turns out the problem is the script is hard coded to assume all files are located on the drive C:. Which mine are not. My Flash is installed on C: drive but my files are located on D:. Once I moved everything to my C: drive it worked fine.

Gravatar CODE ENDEAVOR » JSFL: Publish With Exclude Classes (CS3,CS4)

[...] brings "publish with exclude classes" support to CS3, and CS4. Originally written by Matthew Tretter. I cleaned up the script, and fixed problems with file search logic. As well as fixing support for [...]

Gravatar bilbo

you can make swc files in flex and use them to compile against in cs3 too.

Gravatar J.

this is excellent !
Just in case, your link is broken, the file is here : http://exanimo.com/files/Publish%20(obey%20_exclude.xml)%202008-06-19.zip

Gravatar jfroom

In Flash CS4 OSX, I initially get a JSFL error message that PointlessThing.as cannot be renamed. I changed permissions on the file so the Group and Everyone have read/write. The next error is pushed into the output console:

Warning: unable to restore file file:///Users/jfroom/Desktop/STUFF/exanimo/examples/com/exanimo/Publish (obey _exclude.xml)/src/PointlessThing.as

The SWF compile still succeeds, but the classes are still included in the example.swf build. Also, PointlessThing.as.bkup is left in the SRC folder.

Sorry I don't have any further time to contribute to this debugging. Would love to hear any follow up. This tool is desperately needed as a native feature in CS5.

If anyone else needs a work around, I've detailed one here:
http://www.gaiaflashframework.com/index.php/topic,2743.0.html

Based on Jesse's Warden's post:
http://jessewarden.com/2009/05/creating-modules-in-flash-cs4.html

Gravatar jfroom

Oops take that back, the file permissions is still unavoidable. The rename error happens and then that error is thrown to the output console.