Prototype source and example checked into http://svn.apache.org/viewvc/incubator/flex/whiteboard/aharui/flexjs
- This document is a work in progress *
Overview
With the donation of FalconJS, the Apache Flex community has an important tool in the pursuit of getting Flex to run without Flash/AIR. There are multiple possible approaches to achieving this goal. I have chosen one approach. The basic premise is that Apache Flex can provide parallel frameworks in AS and JS (and potentially other languages) that abstract the differences between the platform into components in the framework. MXML is used to declaratively assemble components, and AS is used as the glue code and business logic. FalconJS converts the AS code to JS and the JS framework is swapped in instead of the AS framework and suddenly your Flex app runs in the browser.
![WorkFlow](/confluence/download/attachments/30743408/WorkFlow.png?version=2&modificationDate=1354118092000&api=v2)
Example
In the example, the source in the FlexJSUI project has been compiled into a SWC and used by the FlexJSTest app. Don't worry about the sub-folders in the FlexJSUI project just yet. The key point is that there is a lightweight Button and Label component in FlexJSUI.
(Note that neither the MXMLC or Falcon compilers produce the desired output right now. We will change Falcon to produce the desired output, so the conversion from MXML to AS is a bit of demo "magic" right now)
The FlexJSTest app has a model, a controller, and an initial view. The MXML for the app might look like it does in FlexJSTestMXML.mxml:
<basic:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*" xmlns:basic="http://ns.apache.org/flex/basic" xmlns:html="http://ns.apache.org/flex/html" xmlns:models="models.*" xmlns:controllers="controllers.*"> ... <basic:initialView> <local:MyInitialView /> </basic:initialView> <basic:model> <models:MyModel /> </basic:model> <basic:controller> <controllers:MyController /> </basic:controller> </basic:Application>
The app consists of an initial view, a model, and a controller. The MXML for the initial view might look like it does in MyInitialViewMXML.mxml:
<basic:ViewBase xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:basic="http://ns.apache.org/flex/basic" xmlns:html="http://ns.apache.org/flex/html" > <basic:Label id="lbl" x="100" y="25" text="{model.labelText}" /> <basic:Button text="OK" x="100" y="75" click="dispatchEvent(new Event('buttonClicked'))" /> </basic:ViewBase>
The developer can develop and test the code in Flash/AIR. Then, the developer can run all of this code through FalconJS. The result is in the examples/FlexJSTest folder. There is an index.html which, instead of using SWFObject and loading the FlashPlayer which loads a SWF, simply includes the JS equivalents of the Application, ViewBase, Label and Button tags used in the app. These can be found in js/framework.js for now.
The JS code outside of the js folder was actually generated by FalconJS from the AS files in FlexJSTest. Again, the FlexJSTest.as and MyInitialView.as are hand-generated from FlexJSTestMXML.mxml and MyInitialViewMXML.mxml since Falcon can't generate such code yet, but I already have code that works like that and plan to integrate it into Falcon soon. So this portion of the demo is real. Given a set of AS files that generate a running (albeit simple) SWF (you can compile FlexJSTest.as into a SWF), you can run the same AS through FalconJS, set up an index.html to load the JS equivalents of the AS components and see the same app run in the browser. I have it working in FireFox on the Mac. I have not tried other browsers yet.
For sure, the UI does not look the same. I'm not sure we can ever guarantee that exactly, but we will do what we can.
And then, if you want, you can install Cordova/PhoneGap, set up a simple project, and swap out the default index.html and .js files for the ones in the example folder and watch the same UI show up in one of the targets for Cordova. I got it to work on Android. I haven't tried IOS yet.
Building the example
- Create a Flex Library project in FlashBuilder for the src/FlexJSUI folder. It should output a FlexJSUI.swc
- Create an Actionscript-Only project in FlashBuilder for the src/FlexJSTest/FlexJSTest.as folder and file. Don't use the .mxml file as the application as the compilers don't know how to codegen in the "new way". FlexJSTest.as should compile into a runnable SWF. A click on the button should change the text. Note that the SWF is only about 11K!
- Now copy all of the .as files to a folder somewhere.
- Copy the FlexJSUI.swc as well.
- Run FalconJS on the FlexJSTest.as file. You should get a set of .JS files.
- Make a subfolder called js
- Copy the adobe.js from the FalconJS source tree to the js folder
- Copy the framework.js from the FlexJS/js folder to the js folder
- Copy the index.html from the example/FlexJSTest folder
- Run the index.html in a browser (I've seen it run in FireFox on Mac for me).
To get it to run using Cordova/PhoneGap, please download, install and create a simple PhoneGap application according to their "Getting Started" documentation. I used Cordova 2.2.0 and the Android Getting Started guide.
In the simple application sources, I simply replaced the default index.html and JS files with the ones generated above and it ran and worked in an emulator. I haven't tried it on an actual device yet.
Goals and Non-Goals
Non-Goals
Backwards Compatibility with Apache Flex 4.8.
It is not a goal provide for the automatic conversion of any existing Flex apps. They would need to be rewritten on top of this new framework and many APIs will be different, but the goal is to match as much of Flex as possible.
Emulate the Flash/AIR APIs.
It is not a goal to try to reproduce Flash/AIR APIs in JS. (Note that the early prototypes of FalconJS did exactly that, rendering as SVG in the browser).
Allow every possible Flex app to be ported to this framework.
At least initially, you won't be able to use Flash APIs in the AS for an app, so any Flex/Flash app that does really fancy Flash rendering, especially in overlays on the screen may not be feasible in this framework.
Port every AS component to JS via FalconJS.
Some parts of an AS component can be ported to JS via FalconJS, but the parts of the component that use Flash APIs will not port over. Instead, a parallel implementation in JS must be created.
Goals
Use as much existing platform functionality as possible.
Flash comes with a button and text components built in. So does every browser. The lowest-level button in this new framework would leverage the flash.display.SimpleButton in AS, and an Input element with type="button" in HTML/JS. A more complex, skinnable button might still use SimpleButton in AS, but might use Anchor tags with backgroundImage in HTML/JS. This is why it is a non-goal to emulate the Flash APIs. A button via emulation would have to load and run all of the code to emulate SimpleButton/Sprite/DisplayObject etc, not to mention an Accessibility implementation, all of which is already running in the browser. Instead, we will encapsulate the best implementation possible under a given API contract, which for a basic Button is probably just an entity with a "click" event.
Choose APIs that work best on HTML/JS.
Note that the way you add a child to its parent is no longer parent.addChild(child), but rather child.addToParent(parent). This is because the JS equivalents are not display objects and are simply acting on the HTML DOM on behalf of some element. What the component does to the DOM is abstracted. A particular child might need to add a Div around itself.
Also, since Dictionary and weak references don't really exist on HTML/JS, the new framework will not use them on AS and you may have to explictly call release() or some other API on some objects to make them available for garbage collection.
Pay as You Go
Everything should be "pay as you go" or "just in time" or "on demand".
Plan
The initial versions will be relatively feature-poor compared to Flex, but the hope is that the architecture is small enough and modular enough to allow Apache Flex community members, many who are participating in their spare time, to participate without having to be immersed in the internals of the framework.