[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by a.revolution.ultra.blue: One hack I was using to get modules to speak through compilations was using Ray's exporter. Basically, common functions like custom dialogs that cover the screen... If I want them to look nice, but be accessible before I ever access Widget code, I use public static class methods like note(String txt), ask(String question, AsyncCallback response, String ... answers). These methods aren't even in the same package as the code that implements them; they just tunnel through a JS API $wnd.parent.MyExportedAPI. The root API module puts a JS object MyExportedAPI on it's $wnd, then it loads the dll nocache.js files, which implement things like note() and ask(), adding them to MyExportedAPI.Dialog.ask() Finally, each osgi iframe has .nocache.js modules that never access the packages which implement the UI stuff, only static methods that tunnel to $wnd.parent.ME_API {or $wnd.parent.parent...ME_API}. Biggest issue was context. All callbacks from an osgi child of the root must send along it's window variables {NOT $wnd}, and map all the parameters in and out of JSNI. Think: public static native void getFeeling(AsyncCallbackString callback) /*-{ top.MyExportedAPI.ask(How are you, [Good,Great,Alright], { wind: window , callback : callba...@com...asynccallback::onSuccess(Ljava/lang/String;) , err : callba...@com...asynccallback::onFailure(Ljava/lang/Throwable;) }); }-*/; then, to actually perform the callback, in JSNI, x.callback.call(x.wind, 'Great') PROBLEMS {only some of them}: * Memory leaks; adding gwt workspace iframe.contentWindow to every tunneled call could get REAL messy. * Hand coded; it works, but there's piles and piles of boilerplate code; external public static access, a to JSNI bridge method, a from JSNI bridge, and finally, an implementation method. Don't forget @Export boilerplate too! * Tracing errors becomes nearly impossible. Had to make a special, ForeignException so different frames could throw an error and call an asyncCallback.onFailure without ClassCastException. * Accessing osgi subframes {/ls, /dl} without being a child of the root frame = not possible. Power users like to skip straight to the url w/ content, sans fancy multiple-module downloads. * Dlls came in .cache.html, so they didn't block downloads of other code, which I thought was an advantage, but with heavy caching situations, weird page reload bugs happened when the root api changed, but the children did not. * Proxied calls were slow * Event.addNativeEventListener does not work through iframes * Compile times through the roof!! * A giant wad of atrocities I've tried to block out. Trust me, the amount of extra dancing and working you will have to do for dll osgi-like modules will cost you more time than money can replace. And what Ray mentioned before about RPC is that your obfuscated Java objects CANNOT sanely be made translatable unless you RPC encode/decode when tunneling to the root MyExportedAPI. This would mean an encode/decode pair of overhead methods for every paramete or returned object that's not a primitive or JSO. I did all this before runAsync and GWT2.0 was compatible with Appengine, and I TOTALLY ABANDONDED THIS METHOD. It hurt too much to implement. Maybe if I was a generator wizard like Ray it wouldn't be so bad, but at least my package segregation methods made the root API modules transferable to runAsync without worry of external dependancy. ...If you feel like you wasted time reading these run on sentences of mine, do yourself a favor, AND SPARE YOUR CODING TIME, COMPILING TIME AND EXECUTION SPEED: *Monolithic* *Compile* *Is* *The* *Only* _efficient_ *Way* *To* *Obfuscate*, *Split* *And* *Link* *Independent* *Modules*. Any other way means a translation layer and jumping through lots of unnecessary hoops! For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by Evelyne24: Hi, I have a question regarding Code Splitting + DI with Guice/Gin. I have a module that looks like this: public class Module { private Thing thing; private ProviderOtherThing provider; // Guice @Inject public Module(Thing thing, ProviderOtherThing provider) { this.thing = thing; this.provider = provider; } } I am trying to split the code for this class, so I inserted a call to GWT.runAsync directly in the constructor. But the code for Provider gets pulled in. Any idea how can I combine DI with Guice/Gin and still be able to split the code like I want? Thanks in advance. Evely For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by cromwellian: Not currently. GWT Exporter was created under the paradigm that it only exports what is explicitly requested, or what is absolutely necessary. I felt at the time that 'inheriting' annotations could lead to a lot of bloat, as well as asking the TypeOracle to give you all subtypes can cause performance issues in Hosted Mode. I planned on adding module parameter 'exportAll', where you don't even have to invoke GWT.create() on each class to export, but rather, there would be a module entry point which triggers a special generator that finds every single class in the classpath with @Export annotations and exports them automatically. There are some people who would like this as an ease of development option. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by lineman78: I have used Ray's GWT Exporter and I believe that you could use this to achieve what you want with plugability while also allowing the compiler to do it's optimizations. One thing I haven't experimented with that Ray would have to answer is if you could add the exporter annotations to the interface or abstract class so that you would not have to re-write them all for each of the modules. I am currently looking at doing a similar thing, but am still researching/designing how I am going to implement it. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by brett.wooldridge: Just a message to the Google GWT team that while I appreciate the theoretical utility of pruning unused methods, especially as applicable to the GWT core UI classes themselves, the applicability to end-user code is likely much less. I routinely run dead code analysis against my source and remove unused methods. So, while it's nice that the compiler would do that for me, it is certainly not a necessity. If a developer's code is too big because of dead code, it should be on his/her shoulders to fix it themselves. If somehow we (end-users) could control which modules were pruned of un-invoked methods it may serve to solve part of the problem. A user such as m.zdila who would like their user's plugins to have full access to the UI component APIs could turn off (all?) pruning. Sure, maybe the result would be a 2meg JavaScript file, but that's his choice. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by cromwellian: I'm not a GWT team member, but I'll comment. It's not just pruning unused methods. It also affects obfuscation and a number of other things that make 'separate compilation/linkage' a difficult prospect. In order for N different separately compiled programs to be linked at runtime, they'd all have to agree upfront on what the names of every publicly available class, method, and field were in the output ahead of time. This would have the effect of lengthening the names of most of the identifiers, further ballooning code. Then there's inlining and type-tightening. Currently, the compiler is able to detect when a method is not polymorphic (no overrides), and turn it into a static method. Moreover, in many cases, it can inline this method. Compile time linkage would prevent this, and the compiler would be forced to conclude that any non-final method can potentially be overriden, disabling inlining and prototype-chain reduction effects. There are lots of other problems to. You're essentially asking GWT to run in Java to Javascript translator mode rather than Java to Javascript compilation mode, akin to the way hand coded Javascript apps are architected. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by hbrucejohnson: @brett: What Ray said. Also, we don't want to create the web equivalent of DLL Hell, which is a very easy situation to get into. Finally, and most importantly, runtime modularity simply has a really high performance cost because HTTP round-trips over the internet are inevitably slow and so we strive to encourage architectures that avoid them. All that said, I think there are a few things we'll do before long (e.g. making it easy to expose JS-callable APIs from GWT modules, like Ray's gwt-exporter) could go a long way toward providing some amount of dynamic pluggability without sacrficing too much in the way of performance. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by m.zdila: @br: We can compile together the client code for all the current modules, but it would not be very OSGi conforming. For example, imagine that some client bought our product including only some of the modules. It would not be very clean to include client code for all the existing modules as one monolithic build. Even if we gave him only the client code for the bundles he bought, then if he would buy additional bundle(s) and dynamically install it to the running system, there would be no chance to add the additional client side part to the existing monolithic build. Simply, each server-side user bundle should have its client module counterpart so they can be dynamically added/removed without recompiling (all) the client. Currently, as described in my first post, the shared workspace code gets duplicated. And exactly this is what makes traversing between modules slow - the JS code must be dowloaded every time (if not cached), parsed, and the workspace initialization code must be run. This way the monolithic build give us the opposite of the desired speed improvement. I admin that I don't know much about the optimization internals. Despite of that I dare to imagine that (in a near future) it would be possible the common workspace module to be separated from the view modules. The optimization can stay within the single module (build). The interface between workspace and view is governed by the Java interfaces (or maybe even the classes) and so the compiler can take it to the accound when optimizing. I personally would rather have this functionality even if the code would not be as much optimal as possible ;-). In any case, currently we can live just OK with our current solution. Good luck! For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by cromwellian: The problem is, if you support separate compilation, the compiler can no longer make assumptions about which methods in your code base are 'live' (are going to be called) and which are 'dead' (are never called), it would be forced to include them on the chance that they might be called in the future by some third party module. This would massively bloat the size of the JS output as well as hamper other optimizations like inlining which depend on knowing things like that if an interface I is implemented by classes A and B, and B is never used, than I == A. This comes up frequently with say, List/ArrayList/LinkedList where LinkedList is rarely if ever used. In my opinion, what you really want is some kind of message bus or RPC mechanism, so that differently compiled packages can communicate over some interface. In this case, the amount of shared code that must be replicated can be kept to a minimum. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by m.zdila: cromwellian: I don't understand how could the RPC solve my problem. Maybe what I would like to have is currently very complicated in the GWT. I am accepting it and can live with that. Long time ago I was using DOJO and I was dynamically loading the views to the workspace. I know it has nothing to do with the GWT, I only want to tell you that some other frameworks can do it. (Un)fortunately I wouldn't use any JS-only framework even if it had such an feature :-). Anyway it would be great if GWT had some means to do the true dynamic code loading. It doesn't have to be necessairly transparent for the developer. I wouldn't mind to somehow explicitly mark some code interface points or something... For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by hauke.kopf: We are also searching for solution to dynamically extend the GUI produced via GWT. Regarding Cromwellian's comment about the compiler optimizations and the static analysis of what code parts are live or dead, I would say that what we want is something like JARs for GWT. Have the base GWT application compiled as one or more JAR-like packages, develop you extensions/plugins against the main application's API and package them as JAR-like files. At runtime of course you as the application owner must make sure that all required JARs/bundles are present. But hey, that's exactly what people know from JAVA apps. If you miss a JAR file you will get a ClassNotFoundException. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by m.zdila: Hello. This is certainly a nice feature, but one not requiring a monolithic compile would be that just great. Our application is built on top of OSGi. When a new module is added a new menu item appears in the GUI to access that module GUI (under different URL). Currently we must compile each OSGi module with the common Workspace library project and so the common Workspace part is duplicated over the modules and so needs to be loaded together with each module code. This is because of the monolithic build. Much nicer would be a separate Workspace module that just lazy-loads its (OSGi based) dynamic view modules on demand (menu item clicks). Is there any plan to make possible to do it like this? Thanks in advance. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by JasonThrasher: Above: The -soyc flag is currently only available on the GWTCompiler entry point, not the new Compiler entry point. Is this still true? It seems that the new Compiler takes the -soyc flag, but I don't see any output generated, other than messages saying that the Story is being created, eg: [INFO] Compiling [INFO] Creating Split Point Map file for SOYC [INFO] Done [INFO] Creating Stories file for SOYC [INFO] Done [INFO] Creating Dependencies file for SOYC [INFO] Done For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by JasonThrasher: Above: The -soyc flag is currently only available on the GWTCompiler entry point, not the new Compiler entry point. Is this still true? It seems that the new Compiler takes the -soyc flag, but I don't see any output generated, other than messages saying that the Story is being created, eg: {{{ [INFO] Compiling [INFO] Creating Split Point Map file for SOYC [INFO] Done [INFO] Creating Stories file for SOYC [INFO] Done [INFO] Creating Dependencies file for SOYC [INFO] Done }}} For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by JasonThrasher: Above: The -soyc flag is currently only available on the GWTCompiler entry point, not the new Compiler entry point. Is this still true? It seems that the new Compiler takes the -soyc flag, and the old GWTCompiler does not take the -aux flag. But I don't see any output generated by the Compiler, other than messages saying that the Story is being created, eg: {{{ [INFO] Compiling [INFO] Creating Split Point Map file for SOYC [INFO] Done [INFO] Creating Stories file for SOYC [INFO] Done [INFO] Creating Dependencies file for SOYC [INFO] Done }}} For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by JasonThrasher: Above: The -soyc flag is currently only available on the GWTCompiler entry point, not the new Compiler entry point. On the current GWT 2.0 HEAD off of SVN, -soyc are supported for the Compiler. Also, -aux has been removed, being replaced by -extra. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by mirceade: I know this must sound dumb: If I have a pre-compiled core module and want to compile and add an extension module on the fly (WITHOUT the core module's source code being available) will this feature make it possible? For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by rj...@google.com: I'm afraid not. runAsync still relies on a monolithic compile. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by adam.tacy: A suggestion for the common coding patterns: I've found that I needed three cases more often than not and so extended the ModuleClient interface as follows: public interface ModuleClient { void onLoad(Module instance); void onAlreadyLoaded(Module instance); void onUnavailable(); } The addition is the onAlreadyLoaded() method which can be used if the code is already loaded. This is useful if you want to do additional work on the first load and only a subset or different work if already loaded. A very simple example is where the RunAsync code might return a widget. The onLoad() could add that widget to the DOM and then configure some items on it, the onAlreadyLoaded() method may not want to add the widget to the DOM and only show it. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by adam.tacy: A suggestion for the common coding patterns: I've found that I needed three cases more often than not and so extended the ModuleClient? interface as follows: {{{ public interface ModuleClient { void onLoad(Module instance); void onAlreadyLoaded(Module instance); void onUnavailable(); } }}} The addition is the onAlreadyLoaded() method which can be used if the code is already loaded. This is useful if you want to do additional work on the first load and only a subset or different work if already loaded. A very simple example is where the RunAsync code might return a widget. The onLoad() could add that widget to the DOM and then configure some items on it, the onAlreadyLoaded() method may not want to add the widget to the DOM and only show it. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---
[gwt-contrib] Comment on CodeSplitting in google-web-toolkit
Comment by inventoriffic: This looks amazing. For more information: http://code.google.com/p/google-web-toolkit/wiki/CodeSplitting --~--~-~--~~~---~--~~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~--~~~~--~~--~--~---