Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace document.write('<script ...>') with document.createElement('script') #9797

Closed
jiakuan opened this issue Jan 30, 2023 · 2 comments
Closed

Comments

@jiakuan
Copy link

jiakuan commented Jan 30, 2023

GWT version: 2.10.0
Browser (with version): Chrome
Operating System: Version 109.0.5414.119 (Official Build) (x86_64)


Description

I'm using SingleScriptLinker to produce a single Javascript file, and the generated JS code contains:

    $doc_0.write('<script id="' + markerId + '"><\/script>');

Which causes errors when the GWT output JS is used in a Chrome Extension:

Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.

According to the latest documentation about document.write:
https://developer.mozilla.org/en-US/docs/Web/API/Document/write

Use of the document.write() method is strongly discouraged.

I'm wondering if it's a good idea to replace the following two lines:

    $doc.write('<script id="' + markerId + '"></script>');
    markerScript = $doc.getElementById(markerId);

https://github.com/gwtproject/gwt/blob/main/dev/core/src/com/google/gwt/core/linker/SingleScriptTemplate.js#L96-L97

with:

    markerScript = $doc.createElement('script');
    markerScript.id = markerId;
    $doc.body.appendChild(markerScript);

If this makes sense, there are a few other script templates needing similar changes.
https://github.com/gwtproject/gwt/search?q=%24doc.write%28%27%3Cscript&type=code

Steps to reproduce

Inspect the generated GWT Javascript code, you will see doc.write in it.

Known workarounds

I've tested the new template in a custom linker, which avoided document.write in the generated Javascript, hence eliminated such errors in Chrome Extension.

Links to further discussions
@tbroyer
Copy link
Member

tbroyer commented Jan 30, 2023

If the gwt.xml has <script> elements, they'll be injected using document.write too (IIRC, this is/was to guarantee execution order):

private static String generateScriptInjector(String scriptUrl) {
if (isRelativeURL(scriptUrl)) {
return " if (!__gwt_scriptsLoaded['"
+ scriptUrl
+ "']) {\n"
+ " __gwt_scriptsLoaded['"
+ scriptUrl
+ "'] = true;\n"
+ " document.write('<script language=\\\"javascript\\\" src=\\\"'+base+'"
+ scriptUrl + "\\\"></script>');\n" + " }\n";
} else {
return " if (!__gwt_scriptsLoaded['" + scriptUrl + "']) {\n"
+ " __gwt_scriptsLoaded['" + scriptUrl + "'] = true;\n"
+ " document.write('<script language=\\\"javascript\\\" src=\\\""
+ scriptUrl + "\\\"></script>');\n" + " }\n";
}
}

AFAICT, your proposed change won't work:

  • if the script is in the head of the page (document.body doesn't exist yet)
  • might then break the following lines that walk up the DOM trying to find the currently executing script.

There's definitely room from improvement, and these templates are quite old, but if they don't work for you I'd suggest creating your own linker. But IIRC the xsiframe linker works for browser extensions and shouldn't use document.write.

@jiakuan
Copy link
Author

jiakuan commented Jan 30, 2023

I was guessing probably document.write was used to guarantee execution order. If we could figure the correct place to inject the script tag, then perhaps we could use the DOM API instead of the document.write to create the script element.

jhickman added a commit to jhickman/gwt that referenced this issue Aug 15, 2023
- replaces PR gwtproject#9814
 - due to currentScript not being fully supported, wrapped in conditional
- fixes issue gwtproject#9797
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants