Optimizing Flex when multiple modules are used - apache-flex

I have a Flex application where load time is extremely important (consumer site). i want to be able to get something up on screen and then allow additional modules to be loaded as necessary.
The issue I'm facing is that the sum total of all the modules is much larger than if i were to include all the components in a single .swf file.
Its pretty obvious why. For instance the classes needed for web service access seem to take about 100kb. If I dont use those classes in my main.swf then they'll be included in EVERY module that uses them. So if I have 5 modules thats an extra 500kB wasted.
In theory I want 3 levels
main.swf - minimum possible layout / style / font / framework type stuff
common.swf - additional classes needed by module 1 + module 2 (such as web services)
module1.swf - module 1 in site
module2.swf - module 2 in site
I dont know if this is even possible.
I'm wondering if I can load swz/swf files for portions of the framework instead of the entire framework.
I really need to get my main app size down to 200Kb. It grows to 450kb when I add web services and basic datagrid functionality.
Any lessons learned would be appreciated.

I know this was awhile ago, but I figured I'd post another response in case anyone is still looking for an answer on this.
I've been looking into optimizing Flex apps and, after some checking into it, have decided to use Modules. Primarily 'cause they have such good options for optimization.
The two mxmlc commands you need are:
mxmlc -link-report=MyAppReport.xml MyApp.mxml
and
mxmlc -load-externs=MyAppReport.xml MyModule.mxml
My external swf (using the Flex Framework) is now only 21k. It's doing much (yet), but even as it does more and more, it will continue to use resources from the main app code.
Here's the batch file I created to speed up the process (you have to have put mxmlc in your Environment Path variable for it to work like this. Control Panel -> System -> Advanced -> Environment Variables, Edit the Path System Variable, adding the path to your mxmlc (requires a reboot)):
cd C:\Projects\MyProject\Develop\Modules
mxmlc -link-report=MyAppReport.xml C:\Projects\MyProject\Develop\Source\Main.mxml
mxmlc -load-externs=MyAppReport.xml MyModule.mxml
move /Y MyModule.swf ..\Runtime\Modules
More info here:
http://livedocs.adobe.com/flex/3/html/help.html?content=modular_4.html
Hope that helps!

Flex is a bit of a pig when it comes to file size. There really is only one way to get your app sizes down and that is to use an external swz for the framework. There is an Adobe Devnet article on Improving Flex application performance using the Flash Player cache which I recommend you read.
On a project I worked on we had problems with our preloading module sucking in classes that we didn't want. What we had to do was create interfaces to the classes that resided in the other modules and reference them that way. When the module is loaded we simply assigned a reference to the IApplicationModule in order to call our initialization code.
Also look into putting your classes into a seperate SWF file and then use ApplicationDomain to get access to the classes
(this code taken from this forum post which explains how to access classes loaded from modules in Flex)
private function loadContent(path:String):void
{
var contentLoader:Loader = new Loader();
contentLoader.contentLoaderInfo.addEventListener(
Event.COMPLETE,
loadContent_onComplete);
contentLoader.load(new URLRequest(path));
}
private function loadContent_onComplete (event:Event):void
{
var content:DisplayObject = event.target.content;
if(content is IFlexModuleFactory)
{
var content_onReady:Function = function (event:Event):void
{
var factory:IFlexModuleFactory = content as IFlexModuleFactory;
var info:Object = factory.info();
var instanceClass:Class = info.currentDomain.getDefinition(
info.mainClassName) as Class;
addChild (new instanceClass ());
}
content.addEventListener ("ready", content_onReady);
}
else
{
addChild (content);
}
}

There is an option on the command-line compiler to exclude class definitions that are already compiled into another swf. It works like this:
Compile the Main Application (which contains a loader) and opt to generate a report.
Compile the Module and opt to exclude classes in the above report.

You could look into the ModuleLoader class, maybe you can load up your core stuff in the first 200kbs then load the rest when and if it's needed.
Also it's worth bearing in mind that any SWC's you use are embedded at compile time whereas any SWF's are loaded at runtime.

Related

call twirl template from ScalaJs

The play framework documentation says (https://www.playframework.com/documentation/2.6.x/ScalaTemplates): You can then call this from any Scala code as you would normally call a method on a class:
val content = views.html.Application.index(c, o)
Is there an easy way to call twirl templates within ScalaJs for a
crossProject(JSPlatform, JVMPlatform).crossType(CrossType.Pure)
Given that Twirl, the templating framework of Play, supports Scala.js, it should relatively simple. The only thing is that, by default, Twirl will not look for templates in the shared source directory. So you'll need to configure its source directories, as explained in its readme, using something like:
sourceDirectories in (Compile, TwirlKeys.compileTemplates) +=
baseDirectory.value.getParentFile / "src/main/twirl"

Using embedded WebResources throughout Webresource.axd

The question's simple: how could one use embedded resources in asp.net applications? What are the steps to include a resource in the assembly, and how to reference it? What are the gotchas that could be encountered?
Edit: For a version without referencing Page and ClientScript, see What is the right way to handle Embedded Resources on a Razor View?
After spending a half of a day I've learned these:
to embed a resource one needs to set it's Build Action to Embedded Resource (in VS Solution Explorer rightclick the file -> Properties)
next AsssemblyInfo.vb must be modified to make this resources available for WebResource queries. Add [Assembly: System.Web.UI.WebResource("MyWebResourceProj.Test.css", "text/css")] to AssemblyInfo.vb located in MyProject folder of the project.
The name consists of root namespace/assembly name +'.'+filename. To be 100% sure of the name, use the following code snippet to look it up:
Dim resNames = Assembly.LoadFile("YourDll.dll").GetManifestResourceNames()
Note that the assembly's Root Namespace must be the same as the Assembly Name (this took me about 4 hours to realize. At least with .Net v4 that is the case)
If there are references inside the css ( <%=WebResource("NS.image.jpg")%> ) than pass PerformSubstitution:=true for that css's WebResource attribute.
Referencing the resource can be done with Page.ClientScript.GetWebResourceUrl(GetType(MyWebResourceProj.ConssumingPage), "MyWebResourceProj.Test.css")
Note that instead of GetType(Typename) one could use Me.GetType(), but again, that won't work if the class is inherited, so beware!
Resources:
Debugging ASP.NET 2.0 Web Resources: Decrypting the URL and Getting the Resource Name
Using embedded resources through WebResource.axd is a pain in the neck, as you can see from your own answer. You have to keep assemblyinfo.vb|cs in sync, and it always seems damn near impossible to get all the namespace & assembly names right in all the right places.
When you finally get it to work, your reward is an include script line that that looks like a core memory dump.
I suggest an alternative. Write yourself a very simple web handler (e.g. MyResourceLoader.ashx. Then add a method to your class that simply serves it's own embedded resources, in whatever way you think is meaningful. You can use reflection to get the classes, like WebResource does, or just hardcode whatever you need into your loader, if it's just for a specific purpose. A public method in your class might look like:
public static Stream GetResource(string resourceName) {
// get the resource from myself, which is easy and doesn't require
// anything in assemblyinfo, and return it as a stream. As a bonus,
// you can parse it dynamically or even return things that aren't
// just embedded, but generated completely in code!
}
Or if you decide to make something more general purpose, you can get all fancy and return more data using a class, e.g.
class ResourceInfo
{
public Stream Data;
public string MimeType;
public string FileName;
}
Now you have the ability to serve up your embedded resources any way you want, e.g.
<script language="javascript" src="/MyResourceLoader.ashx/MyControlScript.js">
I think MS made a mess of that WebResource business. Luckily its' pretty straightforward to do your own thing.

Prism, Unity - Converting from MEF

I recently converted from MEF to Unity - for various reasons.
I previously had a IMenuService object in a module that I exported with MEF and imported in other modules. I believe what I have to do with Unity is take the unity container in as a parameter to the constructor of my module, then use that to register the IMenuService , however, I'm not sure how to do this (what argument type? do I have to first register the container in the bootstrapper to import it into the module?)
Also, in MEF there are ModuleDependency attributes to make sure other modules are loaded first... what would be the equivolent in Unity?
EDIT: figured out the IUnityContainer argument... however, still curious about the seconds part... dependencies
as you have figured out, the type you should have your modules depend on to IUnityContainer. You don't really have to register the container with itself in order to be able to work with it in the modules (while you can do it if you wanted, and to make things clearer). And last, module dependencies are independent from the IoC container you're using, so it should work just fine. You can as well configure the ModuleCatalog from xaml using:
protected override IModuleCatalog CreateModuleCatalog()
{
return ModuleCatalog.CreateFromXaml(new Uri("catalog.xaml", UriKind.Relative));
}
and in the catalog.xaml file, you can specify the dependencies using the DependsOn property of the ModuleInfo.
hope this helps :)

Force Flash Builder 4 to compile all source files

According to the answers to this question here, the reason why I'm not seeing errors as I work in Flash Builder is that FB is "optimizing" them out because they aren't referenced at any point in the code execution. Is there an option to force Flash Builder to compile all files regardless of whether they're used in the software? This would make my development process a lot more intuitive.
The only way to do this is to actually reference the class somewhere in code that you know actually is being compiled, such as the Document Class in a .fla, or your Main.as file in a pure AS3 project. It can be as simple as declaring a variable of the given type, even if no value is ever assigned to it.
private var complieMe:OtherwiseUnreferencedClass;
// ^ This will cause your class to be compiled.
You need to reference each class somewhere in your project. The easiest/shortest way I've found to do this is to add an import followed by the class name in some common place, such as a script block in Main.mxml, although it really doesn't matter where:
import some.package.MyClass; MyClass;
Hope that helps.

Using external SWFs in a Flex application - duplicating MovieClip?

I'm working on an Flex application which uses many objects, e.g. LEDs, bulbs, gauges created in Flash. The objects internally consist of several small MovieClips and have their own logic inside. One of the initial requirements was that the objects have to be loaded at runtime, thus they were exported as SWF, not SWC. However, we ran into problem when we tried to duplicate loaded SWF. It turned out that MovieClip class doesn't have neither copying constructor nor method that would allow us to clone existing MovieClip. This way we'd end up loading an object every time from hdd, which involves a lot of overhead. Is it possible that language like ActionScript 3 doesn't have such a mechanism? Have we missed something out? If not, am I correct that the only solution is to use Flash Component Kit, make some custom components and include them as SWC at compile time?
After you load the MovieClip is it possible to use getDefinitionByName() as shown here?
http://livedocs.adobe.com/flex/3/langref/flash/utils/package.html#getDefinitionByName()
You are correct in that there is no built in way to duplicate a movieclip.
There are however work arounds. The esiest way as I see it is to give the movieclips classes.
You don't have to make the actual classes. Just write any name in the class field when setting up linkage on the top most movieclip that needs to be copied.
So a name for you LED movieclip, another name for the bulb etc.
The benifit is that now you have a class that you can initiate objects from.
No when you grap one of the movieclips you can duplicate it with the following method:
public function DuplicateDisplayObject(dO:DisplayObject):DisplayObject
{
if(dO == null)
return null;
var dOClass:Class = Object(dO).contructor;
return DisplayObject(new dOClass());
}
This assumes of cause that you can actually get a hold of one of the movieclips first. And mind you that it doesn't copy the state of the movieclip.
Another more importent note is that this only works if the you link the movieclips to classes. The classes doesn't have to exist (flash will create empty classes for you).
Other solutions could be:
Compiling against the classes without
including them (see the
"external-library-path" tag for the
flex compiler), and load the them at
runtime (from swf).
Compiling against the classes as a
RSL (Runtime Share Library) the swc
will be loaded at runtime.
Adobe has more info on how to do that, should be easy to find on their website.
A more exotic solution would be copy the bytecode of an object. Not sure if that would work with something on the displaylist, properly not.
About the solution using getDefinitionByName():
If I remember correctly you still need to give the movieclips fake classes, since getQualifiedClassName only returns MovieClip class. But I could be wrong.
Another solution:
private function duplicateImg(sourceLoaderInfo:LoaderInfo, target:Image):void
{
var ba:ByteArray = sourceLoaderInfo.bytes;
var dupCliploader:Loader = new Loader();
dupCliploader.contentLoaderInfo.addEventListener(
Event.COMPLETE, bytesLoaded);
dupCliploader.loadBytes(ba);
}
private function bytesLoaded(event:Event):void
{
var mc:MovieClip = event.currentTarget.content as MovieClip;
_img.source = mc;
_img.width = mc.width;
_img.height = mc.height+5;
}

Resources