1

GWT 编译器由于代码拆分而产生代码片段(请参阅此处的详细信息)

初始下载文件命名为{alphanumeric}.cache.js(例如1805B2053A824F148DB6D05B2186F955.cache.js)和下图中的其他片段{number}.cache.js(例如1.cache.js)。

GWT 代码片段

我正在尝试使用 Service Worker 开发 GWT 应用程序,因为我希望该应用程序可以离线工作。一旦缓存并离线,初始下载文件的 GET 请求会触发 ServiceWorker 中的 FETCH 事件,但单个代码片段不会触发该事件。出于某种原因,他们似乎绕过了 Service Worker。

如需演示,请查看https://gwt-pwa-demo.herokuapp.com/pwademo.html上的应用程序。这是一个使用 Service Worker 的 GWT 应用程序。这不是我的应用程序,我只是将其用于演示。

当您加载应用程序时,所有文件都将被缓存。没有从 chrome 开发工具离线,并刷新应用程序。该应用程序仍然显示,您会注意到初始下载文件是从 Service Worker 加载的。现在点击 Paris/Berlin/London,它将加载片段 1.cache.js 等等。请注意,这些来自磁盘缓存,而不是通过 ServiceWorker 缓存存储。如果您查看控制台输出,您不会看到从 ServiceWorker Fetch 事件打印的这些片段的日志。

为了更清楚地说明,该应用程序脱机工作只是因为从磁盘缓存中提取了片段。如果磁盘缓存中不存在这些片段,则应用程序将无法运行。即使碎片存在于缓存存储中,由于 ServiceWorker 无法拦截这些请求,它们也不会被加载。请按照以下步骤查看实际情况。

  1. 假设您已经加载了一次应用程序,请打开开发工具 -> 应用程序 -> 清除存储并清除站点数据。确保缓存存储中的缓存也被清除。
  2. 现在再次加载应用程序https://gwt-pwa-demo.herokuapp.com/pwademo.html
  3. 将再次创建缓存,您将在缓存中看到片段。
  4. 在您的开发工具打开时,使用 Chrome 中的“空缓存和硬重新加载”重新加载应用程序。
  5. 这将清除磁盘缓存,但缓存存储仍然存在。
  6. 离线并刷新应用程序,初始应用程序仍从缓存存储加载。
  7. 但是当您单击触发加载代码片段的巴黎或伦敦时,它会失败。

在此处输入图像描述

4

2 回答 2

2

您必须使用 xhr 请求加载片段。

1)首先你必须扩展 CrossSiteFrameLinker

/**
 * Created by Gernot Pansy <gernot.pansy@ut11.net> on 07.08.17.
 */
@LinkerOrder(LinkerOrder.Order.PRIMARY)
@Shardable
public class ProgressiveWebAppLinker extends CrossSiteIframeLinker {

    @Override
    public String getDescription() {
        return "Progressive-Web-App";
    }

    @Override
    protected String wrapDeferredFragment(final TreeLogger logger, final LinkerContext context, final int fragment,
                                        final String js, final ArtifactSet artifacts) {
        return js;
    }

    @Override
    protected String getJsInstallLocation(final LinkerContext context) {
        return "com/google/gwt/core/ext/linker/impl/installLocationMainWindow.js";
    }

    @Override
    protected String wrapPrimaryFragment(final TreeLogger logger, final LinkerContext context, final String script,
                                        final ArtifactSet artifacts, final CompilationResult result)
            throws UnableToCompleteException {
        return script;
    }

    @Override
    protected String getJsInstallScript(final LinkerContext context) {
        return "xxxxxxx/progressiveWebAppInstallScript.js";
    }

    @Override
    protected String getJsIsBodyLoaded(final LinkerContext context) {
        return "";
    }

    @Override
    protected String getJsWaitForBodyLoaded(final LinkerContext context) {
        return "";
    }

    @Override
    protected String getScriptChunkSeparator(TreeLogger logger, LinkerContext context) {
        return "";
    }

    @Override
    protected boolean shouldInstallCode(final LinkerContext context) {
        return true;
    }
}

2)您需要修改后的 javascript 安装脚本(progressiveWebAppInstallScript.js):

function installScript(filename) {

    function installCode(code) {
        function removeScript(body, element) {
        // Unless we're in pretty mode, remove the tags to shrink the DOM a little.
        // It should have installed its code immediately after being added.

        __START_OBFUSCATED_ONLY__
        body.removeChild(element);
        __END_OBFUSCATED_ONLY__
        }

        var doc = getInstallLocationDoc();

        var script = doc.createElement('script');
        script.language='javascript';
        script.text = code;
        doc.body.appendChild(script);
        removeScript(doc.body, script);
    }

    sendStats('moduleStartup', 'moduleRequested');
    var xhr = new $wnd.XMLHttpRequest()
    xhr.open("GET", filename);
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
        // Clearing onreadystatechange otherwise it may cause memory leak (e.g. in IE8).
        xhr.onreadystatechange = function() {}; // Clear callback
        if (xhr.status == 200) {
            installCode(xhr.responseText);
        } else if (__MODULE_FUNC__.__errFn) {
            __MODULE_FUNC__.__errFn('__MODULE_FUNC__', new Error("Failed to load " + code));
        }
        }
    };
    xhr.send(null);
}
于 2018-09-25T09:46:03.987 回答
1

好的,我想我找到了 chromium 错误报告 @ https://bugs.chromium.org/p/chromium/issues/detail?id=439697和相关的 ServiceWorker 规范问题 @ https://github.com/w3c/ServiceWorker/问题/612

GWT 通过在内部创建 iframe 来加载代码片段。这些 iframe 不受父 Service Worker 的控制。chrome 错误仍然存​​在,但 w3c 关闭了规范问题 @ https://github.com/w3c/ServiceWorker/issues/1163

于 2017-11-16T09:38:11.643 回答