I am writing (with my team) an GWT application, which parses and represent some domain specific language - for example, plays media presentation with text, video and UI controls
I have experimented with this same question since GWT 1.5 and every time I come up with a more elegant solution they change the linker and break it. The only way that I have come up with that would work independent of linker design is to do exactly what you are talking about and create a new module for ever plug-in. Then use GWT exporter to create an abstract class that plugins must extend that would have an abstract method that would take the root element of the plugin passed to it by the core and populate it. The issue with this method is all plug-in modules must be added to the DOM on the initial load of the page because since 2.0 the iFrame linker relies on a page load event so dynamically added modules wont fully load. So because of this you will want to have the exported population method wrapped in runAsync so that you aren't downloading modules till you use them.
Edit:
Here is a rough example of what I am talking about. Please be aware that I haven't done any GWT in a couple years and there may be a better way of doing this by now.
public final class PluginManager
{
public static final PluginManager INSTANCE = new PluginManager();
private PluginManager()
{
}
private static native void loadPlugin( AbstractPlugin plugin )
/*-{
if (!$wnd.Plugins) {
$wnd.Plugins = {};
}
var name = plugin.@com.example.PluginManager.AbstractPlugin::getName()();
$wnd.Plugins[name] = $entry(plugin.@com.example.PluginManager.AbstractPlugin::load(Ljava/lang/String;));
}-*/;
private static native void unloadPlugin( AbstractPlugin plugin )
/*-{
if ($wnd.Plugins) {
var name = plugin.@com.example.PluginManager.AbstractPlugin::getName()();
delete $wnd.Plugins[name];
}
}-*/;
private static native JsArrayString getPlugins()
/*-{
if ($wnd.Plugins) {
return Object.keys($wnd.Plugins);
}
return undefined;
}-*/;
public static abstract class AbstractPlugin implements EntryPoint
{
@Override
public final void onModuleLoad()
{
PluginManager.INSTANCE.loadPlugin( this );
}
protected final void unload()
{
PluginManager.INSTANCE.unloadPlugin( this );
}
protected abstract String getName();
protected abstract void load( String rootPanelId );
}
}