gwtproject / gwt

GWT Open Source Project
http://www.gwtproject.org
1.51k stars 372 forks source link

Error when a module try to load another one. #910

Closed dankurka closed 9 years ago

dankurka commented 9 years ago

Originally reported on Google Code with ID 902

Found in GWT Release: Snapshot of the SVN trunk taken on 2007/03/22
(upcoming 1.4) 

Detailed description:
I am writing a module that will load other modules on demand.
I am doing like this:
1/ Add dynamically a div with a defined id that fits the new module
requirements.
e.g:    FlowPanel newPanel = new FlowPanel();
        DOM.setAttribute(newPanel.getElement(), "id", newModuleId);
        add(newPanel);
[ The new module will use this id by calling RootPanel.get(newModuleId); ]

2/ Add the new module boot script to the DOM:
e.g:    String scriptName = module.getWebAppUrl() + "/" +
module.getModuleName() + "/" + module.getModuleName() + ".nocache.js";
        startJavascript(scriptName);

    private native void startJavascript(String scriptName) /*-{
        var script = $doc.createElement('script');
        script.type = 'text/javascript';
        script.src = scriptName;
        $doc.getElementsByTagName('body')[0].appendChild(script);
    }-*/;

THE PROBLEM IS: When the boot script starts (e.g: mymodule.nocache.js) it
calls doc.write() that completelly replace the document content.
The SelectionScriptTemplate*.js boot files should be modified to avoid
calling doc.write().

I have modified the SelectionScriptTemplate*.js files in order to make it work.
Those files are provided in attachment. Each modification is marked with
"replaced:".

There is a bug with my modification, the Hosted doesn't start.

Reported by evrignaud on 2007-04-10 14:02:24


dankurka commented 9 years ago
To be more precise, with my modifications, the Web mode works, and the Hosted mode
doesn't start. I will let you adress this problem.

Reported by evrignaud on 2007-04-10 14:21:28

dankurka commented 9 years ago
>> The global meaning of the issue is that an error occurs when the boot script of
the module loaded "on demand" starts.

Finally I found the problem with the Hosted mode.
In fact hosted mode on my host execute Internet Explorer as browser and that's why
it
doesn't work.

I have made to following modifications:

  // replaced: 
  // doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
  var script = doc.createElement('script');
  script.innerHTML = "__MODULE_FUNC__.onInjectionDone('__MODULE_NAME__')";
  doc.getElementsByTagName('body')[0].appendChild(script);

  becomes:

  // replaced: 
  // doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
  var code = "__MODULE_FUNC__.onInjectionDone('__MODULE_NAME__')";
  if(wnd.execScript){
    wnd.execScript(code);
  }else{
    var script = doc.createElement('script');
    script.innerHTML = code;
    doc.getElementsByTagName('body')[0].appendChild(script);
  }

A new version of the SelectionScriptTemplate.js file is provided in attachment.

Reported by evrignaud on 2007-04-12 14:12:40


dankurka commented 9 years ago
>> The global meaning of the issue is that an error occurs when the boot script of
the module loaded "on demand" starts.

Finally I found the problem with the Hosted mode.
In fact hosted mode on my host execute Internet Explorer as browser and that's why
it
doesn't work.

I have made to following modifications:

  // replaced: 
  // doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
  var script = doc.createElement('script');
  script.innerHTML = "__MODULE_FUNC__.onInjectionDone('__MODULE_NAME__')";
  doc.getElementsByTagName('body')[0].appendChild(script);

  becomes:

  // replaced: 
  // doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
  var code = "__MODULE_FUNC__.onInjectionDone('__MODULE_NAME__')";
  if(wnd.execScript){
    wnd.execScript(code);
  }else{
    var script = doc.createElement('script');
    script.innerHTML = code;
    doc.getElementsByTagName('body')[0].appendChild(script);
  }

A new version of the SelectionScriptTemplate.js file is provided in attachment.

Reported by evrignaud on 2007-04-12 14:12:45


dankurka commented 9 years ago
This is not really a supported use case.  Also, workarounds exist (such as loading
the new/child app in an iframe instead of a div.)

Reported by gwt.team.morrildl on 2007-04-13 21:34:34

dankurka commented 9 years ago
The modification that I suggest is very simple and didn't modify the normal boot
behavior (Just replace the doc.write() calls).
I don't understand why it should be a good idea to insert the boot script in an iframe:

1/ You have completely re-written the boot script and it is structured to avoid
javascipt conflicts.

2/ The only goal of the boot script is to create an iframe that will host the GWT
application script.

3/ I noticed that things are going in the way that I suggest (Just looking at the SVN
commit #799:
[ Revision: 799
Author: gwt.team.jat
Date: 16:52:00, vendredi 6 avril 2007
Message:
Add support multiple modules in a single browser window in hosted mode, moving much
of the functionality into platform-dependent code.  Added a unit
test for this functionality, although currently it passes simply by not crashing --
in the future we will add instrumentation for the module loading/unloading code (when
we can easily create new objects under window.external) and verify that it is being
properly handled. ])

I think that the usage that I do is not so far from the general usage.

Following is the patch content of the modification that I made:
_____________________________________________________________________________________

Index: SelectionScriptTemplate.js
===================================================================
--- SelectionScriptTemplate.js  (revision 868)
+++ SelectionScriptTemplate.js  (working copy)
@@ -105,7 +105,10 @@
       thisScript = markerScript.nextSibling;
     } else {
       // try writing my own marker
-      doc.write('<script id="__gwt_marker___MODULE_NAME__"></script>');
+      var script = doc.createElement('script');
+      script.id = "__gwt_marker___MODULE_NAME__";
+      doc.getElementsByTagName('body')[0].appendChild(script);
+     
       markerScript = doc.getElementById("__gwt_marker___MODULE_NAME__");
       if (markerScript) {
         // this script should be the previous element
@@ -259,7 +262,10 @@
 // __SHELL_SERVLET_ONLY_BEGIN__
   // Force shell servlet to serve compiled output for web mode
   if (!isHostedMode()) {
-    doc.write('<script src="' + base +
'__MODULE_NAME__.nocache.js?compiled"></script>');
+    var script = doc.createElement('script');
+    script.src = base + '__MODULE_NAME__.nocache.js?compiled';
+    doc.getElementsByTagName('body')[0].appendChild(script);
+   
     return;
   }

@@ -304,11 +310,25 @@
     strongName += '.cache.html';
   }

-  doc.write('<iframe id="__MODULE_NAME__" style="width:0;height:0;border:0" src="'
+
base + strongName + '"></iframe>');
+  var iframe = doc.createElement('iframe');
+  iframe.id = "__MODULE_NAME__";
+  iframe.style['width'] = '0';
+  iframe.style['height'] = '0';
+  iframe.style['border'] = '0';
+  iframe.src = base + strongName;
+  doc.getElementsByTagName('body')[0].appendChild(iframe);
+  
 // __MODULE_DEPS_BEGIN__
   // Module dependencies, such as scripts and css
 // __MODULE_DEPS_END__
-  doc.write('<script>__MODULE_FUNC__.onInjectionDone(\'__MODULE_NAME__\')</script>');
+  var code = "__MODULE_FUNC__.onInjectionDone('__MODULE_NAME__')";
+  if(wnd.execScript){
+   wnd.execScript(code);
+  }else{
+   var script = doc.createElement('script');
+   script.innerHTML = code;
+   doc.getElementsByTagName('body')[0].appendChild(script);
+  }
 }

 // Called from compiled code to hook the window's resize & load events (the
Index: SelectionScriptTemplate-xs.js
===================================================================
--- SelectionScriptTemplate-xs.js   (revision 868)
+++ SelectionScriptTemplate-xs.js   (working copy)
@@ -65,7 +65,10 @@
     var thisScript, markerScript;

     // try writing a marker
-    doc.write('<script id="__gwt_marker___MODULE_NAME__"></script>');
+    var script = doc.createElement('script');
+    script.id = "__gwt_marker___MODULE_NAME__";
+    doc.getElementsByTagName('body')[0].appendChild(script);
+   
     markerScript = doc.getElementById("__gwt_marker___MODULE_NAME__");
     if (markerScript) {
       // this script should be the previous element
@@ -210,12 +213,17 @@
 // __SHELL_SERVLET_ONLY_BEGIN__
   if (!isHostedMode()) {
     // Force shell servlet to serve compiled output for web mode
-    doc.write('<script src="' + base +
'__MODULE_NAME__.nocache-xs.js?compiled"></script>');
+    var script = doc.createElement('script');
+    script.src = base + '__MODULE_NAME__.nocache-xs.js?compiled';
+    doc.getElementsByTagName('body')[0].appendChild(script);
     return;
   } else {
     // This script cannot run hosted mode properly; redirect to the html version
     // TODO: figure out how to run hosted mode in the main window
-    doc.write('<script src="' + base + '__MODULE_NAME__.nocache.js"></script>');
+    var script = doc.createElement('script');
+    script.src = base + '__MODULE_NAME__.nocache.js?compiled';
+    doc.getElementsByTagName('body')[0].appendChild(script);
+   
     return;
   }
 // __SHELL_SERVLET_ONLY_END__
@@ -235,7 +243,9 @@
 // __MODULE_DEPS_BEGIN__
   // Module dependencies, such as scripts and css
 // __MODULE_DEPS_END__
-  doc.write('<script src="' + base + strongName + '"></script>');
+  var script = doc.createElement('script');
+  script.src =  base + strongName;
+  doc.getElementsByTagName('body')[0].appendChild(script);
 }

 // Called from compiled code to hook the window's resize & load events (the

_____________________________________________________________________________________

Reported by evrignaud on 2007-04-14 12:12:26


dankurka commented 9 years ago
Hi evrignaud,

The reason we use doc.write is to guarantee load order of certain things.  In 1.3,
we
had to do a lot of crazy magic to make sure things loaded in the right order,
including polling on a timer.  With the new system, we can guarantee that everything
will load in exactly the right order.  By everything, I mean multiple modules on the
same page and external script dependencies.  If we tried to remove doc.writing, we
couldn't guarantee any load order anymore.  It would also mean we couldn't compute
the module base URL from the script tag.

Reported by dragonsinth on 2007-04-14 20:51:06

dankurka commented 9 years ago
This modification would be very helpful.

In my case, I'm trying to do a portlet (JSR 286) inside the eXo WebOS. Portlet can
be
loaded anytime, so the use of document.write break it. I was able to make it working
replacing this doc.write and changing the object document a fake object and calling
manually document.onload.
But it's not possible to industrialize without making change in GWT.

The use of an iframe is a possibility, but it's not so nice. 

Reported by jeremi23 on 2007-07-17 12:46:22

dankurka commented 9 years ago

Reported by jgw+personal@google.com on 2008-04-29 14:54:04

dankurka commented 9 years ago

Reported by sumitchandel+legacy@google.com on 2008-05-02 16:54:04

dankurka commented 9 years ago

Reported by bruce+personal@google.com on 2008-10-21 21:54:58

dankurka commented 9 years ago
Closing as a result of issue triage. More information can be found here:

http://groups.google.com/group/google-web-
toolkit/browse_thread/thread/3a7bf1c6a3d35431

Thanks

Reported by cramsdale@google.com on 2009-12-21 16:13:23

dankurka commented 9 years ago

Reported by cramsdale@google.com on 2009-12-21 19:38:26