HowTo: Reduce the size of your Flex app

Flex 2 added a neat little feature which allows you to load Runtime Shared Libraries, from other domains. And since the browser caches these libraries in theory we could all point to a central set of Flex 2 Framework RSLs and users of your application would only have to download the RSLs the first time they went to an application which used them. Before I show you how to make this work, lets talk about the caveats… First and most important, THIS IS UNSUPPORTED BY ADOBE. While the Flex team is working on a better, more permanent solution to this problem, this is really a hack and despite the fact that I am using this in my applications, neither I or Adobe warranty or support the use of this in any way. Second, since there is no failover mechanism, until we find a better home for the RSLs, if you choose to point to my hosted RSLs, your application will be at the mercy of my web server. Third, if someone hacks my web server and uploads new cracked malware RSLs, or uses a man-in-the-middle attack to replace the RSLs in flight, then you (and I) have been p0wned. Fourth, I, James Ward, may have included modified Flex framework files which do bad things, like track user behavior/input and report them back to my server. While I promise I have not done this, if you choose to use these RSLs, you are putting your trust in my promise.

So despite the caveats, I still think this hack is sufficient enough for many applications. Flex engineering is really working hard to make this work for everyone. In the mean time what is outlined here may likely help you to dramatically reduce SWF size. Read on to find out how.

Quick Start

I’ve created 3 RSLs, a small one, with just the dependencies of mx.core.Application and a medium one with what I guessed were the 20 or so most commonly used components, and then a large one with over 30 other components. Each RSL does not include the contents of the smaller RSLs. So if you want to take advantage of this technique using the medium RSL, then you will need to use the medium AND the small RSL. Here is table with the information about the RSLs:

<th>
  Size
</th>

<th>
  SWC
</th>

<th>
  Linker Source
</th>

<th>
  SWC Catalog
</th>
  <td>
    106K
  </td>
  
  <td>
    <a href="http://ws.jamesward.org/framework-2_0_1_b-small.swc">Download SWC</a>
  </td>
  
  <td>
    <a href="http://flexapps.cvs.sourceforge.net/flexapps/hosted_rsls/src/smallLinker.as?view=log">smallLinker.as</a>
  </td>
  
  <td>
    <a href="http://ws.jamesward.org/framework-2_0_1_b-small.xml">Catalog XML</a>
  </td></tr> 
  
  <tr>
    <td>
      <a href="http://ws.jamesward.org/framework-2_0_1_b-medium.swf">medium<a /></td> 
      
      <td>
        160K
      </td>
      
      <td>
        <a href="http://ws.jamesward.org/framework-2_0_1_b-medium.swc">Download SWC</a>
      </td>
      
      <td>
        <a href="http://flexapps.cvs.sourceforge.net/flexapps/hosted_rsls/src/mediumLinker.as?view=log">mediumLinker.as</a>
      </td>
      
      <td>
        <a href="http://ws.jamesward.org/framework-2_0_1_b-medium.xml">Catalog XML</a>
      </td></tr> 
      
      <tr>
        <td>
          <a href="http://ws.jamesward.org/framework-2_0_1_b-large.swf">large<a /></td> 
          
          <td>
            141K
          </td>
          
          <td>
            <a href="http://ws.jamesward.org/framework-2_0_1_b-large.swc">Download SWC</a>
          </td>
          
          <td>
            <a href="http://flexapps.cvs.sourceforge.net/flexapps/hosted_rsls/src/largeLinker.as?view=log">largeLinker.as</a>
          </td>
          
          <td>
            <a href="http://ws.jamesward.org/framework-2_0_1_b-large.xml">Catalog XML</a>
          </td></tr> </table> 
          
          <p>
            Once you have decided which RSL to use, follow these instructions:<br /> 1) Download the SWC for the RSL(s) you want to use from <a href="http://ws.jamesward.org">ws.jamesward.org</a><br /> 2) Fix your build path<br /> 2.1) If you are compiling via Ant or the command line, then specify your external-library-path and runtime-shared-libraries like:
          </p>
          
          <div width="100%" style="background: #cccccc; overflow : auto; padding: 6px;">
flex2-sdk/bin/mxmlc \
  -external-library-path+=build/framework-2_0_1_b-small.swc,build/framework-2_0_1_b-medium.swc \
  -runtime-shared-libraries=http://ws.jamesward.org/framework-2_0_1_b-small.swf,http://ws.jamesward.org/framework-2_0_1_b-medium.swf \
  -o=build/testHostedFlexLibs-medium.swf \
  -file-specs=test/testHostedFlexLibs.mxml
          </div>
          
          <p>
            2.2) If you are using Flex Builder then go to Project -> Properties -> Flex Build Path -> Library Path -> Add SWC -> [Enter or browse to the first SWC] -> Add all the SWCs you will be using. Then select a SWC's RSL URL and select the Edit button. Change the Link Type to "Runtime shard library (RSL)", set the RSL URL to the correct swf url on ws.jamesward.org, deselect the "Auto extract checkbox", and then select the OK button. Repeat this for each SWC. When done, select the OK button to exit the Project Properties. Here is what my Build Path looks like:<br /> <img src="http://www.jamesward.org/wordpress/wp-content/uploads/2006/11/buildpath.png" alt="Build Path" />
          </p>
          
          <p>
            2.3) If you are using FDS, then just add the SWC(s) to your flex/user_classes dir and update the runtime-shared-libraries accordingly in the flex-config.xml file.
          </p>
          
          <p>
            3) Recompile your Flex app (if Flex Builder didn't do this for you automatically) and the file size should be significantly lower!
          </p>
          
          <p>
            4) One more caveat... You have to actually load your application from a web server for it to work. This is due to the Flash local OR network sandbox. Maybe someone can suggest a better workaround.
          </p>
          
          <p>
            <strong>How It Works</strong>
          </p>
          
          <p>
            This all starts with the Preloader. The out of the box preloader doesn't support cross domain loaded RSLs. If you use my hosted RSL(s) then you don't need to worry about this since it includes the patched Preloader. However, if you are interested in really knowing how this all works, or if you want to download the source code and play with it, then here is what you need to do. In order for your application to be able to use the classes in the crossdomain loaded RSL, the Preloader needs to specify the securityDomain for the loaderContext of the RSLs. So in the loadRSL function of my patched mx/preloaders/Preloader.as file I have:
          </p>
          
          <div width="100%" style="background: #cccccc; overflow : auto; padding: 6px;">
loaderContext.securityDomain = SecurityDomain.currentDomain;
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
          </div>
          
          <p>
            The source code I use to build the RSLs is available on <a href="http://sourceforge.net/projects/flexapps">Source Forge</a>. If you want to play with the code, then you will need to copy the Preloader.as from the Flex SDK's source code, update the RSL loaderContext as noted above, and add the import for the flash.system.SecurityDomain class.
          </p>
          
          <p>
            You can also see that I have a <a href="http://ws.jamesward.org/crossdomain.xml">wildcard crossdomain.xml</a> policy file on ws.jamesward.org which allows Flash player to load the RSLs no matter what domain the requesting application is hosted on. One quick note on crossdomain policy files, since I don't think it is said clearly enough, and often enough...<br /> DO NOT EVER PUT A WILDCARD CROSSDOMAIN POLICY FILE ON A DOMAIN IF EITHER OF THE FOLLOWING APPLY:<br /> - THE DOMAIN IS USED FOR COOKIE BASED OR BASIC AUTHENTICATION<br /> - THE DOMAIN IS ON AN INTERNAL NETWORK
          </p>
          
          <p>
            Now about the small, medium, and large RSLs... For now I opted to use just three RSLs to keep it simple. I am using just simple linker classes and compc to create the SWCs, then expanding the SWCs to get the SWF, which is the RSL. You can see all this in the source code, specifically, the <a href="http://flexapps.cvs.sourceforge.net/flexapps/hosted_rsls/build.sh?view=log">build.sh</a> file. I have also guessed at the best way to organize the RSLs (as far as what classes go where), but definitely want to hear what others think.
          </p>
          
          <p>
            Now the fun part... To prove this all works, first go to the <a href="http://www.jamesward.org/testHostedFlexLibs-large-1.swf">test app</a> on www.jamesward.org and watch as the RSLs are loaded from ws.jamesward.org. You should now have all 3 RSLs in your browser cache and if you now go to another <a href="http://www.thebetterside.com/testHostedFlexLibs-large-1.swf">test app</a> on a different domain the application should load much faster since it only needs to load 72K instead of what would have been over 400K (my test app doesn't use all the classes in the three RSLs).
          </p>
          
          <p>
            <strong>The Future?</strong>
          </p>
          
          <p>
            I'd really like to hear feedback if this is a viable hack for those looking to reduce Flex app size. Let me know if you plan to use this technique, or if you don't, why? What should be different? Also, I think someone could further hack the preloader to support failover and md5 checksums. Any takers?
          </p>
          
          <p>
            Thanks in advance for your feedback!
          </p>
comments powered by Disqus
RSL
small