编译和调试

让我们从 GWT 开发的核心原则开始

  1. 如果您的 GWT 应用程序在开发模式下按预期运行...
  2. 并且 GWT 编译器成功地将您的应用程序编译成 JavaScript...
  3. 那么您的应用程序在 Web 浏览器中的运行方式将与在开发模式中相同。

本节的其余部分介绍了开发模式(以前称为“托管模式”)和生产模式(以前称为“Web 模式”),并解释了如何以及何时使用它们。

在开发模式下调试

您将在开发的大部分时间里运行您的应用程序在开发模式中,这意味着您正在与您的 GWT 应用程序进行交互,而它还没有被翻译成 JavaScript。每当您从 Java 集成开发环境 (IDE) 编辑、运行和调试应用程序时,您都在开发模式下工作。当应用程序在开发模式下运行时,Java 虚拟机 (JVM) 实际上正在执行应用程序代码作为编译的 Java 字节码,使用 GWT 管道连接到浏览器窗口。这意味着您的 IDE 的调试工具可用于调试您的客户端 GWT 代码和任何服务器端 Java 代码。通过保持这种传统的“代码-测试-调试”循环,开发模式是快速开发应用程序最有效的方式。

下面是一个典型的开发模式会话

DevModeTypical

在开发模式下启动应用程序

要启动开发模式会话,从命令行运行 ant devmode,假设您有一个由 webAppCreator 生成的 Ant build.xml 文件。

提示:如果您使用的是 Eclipse,您可以使用运行或调试菜单运行 webAppCreator 创建的 <app>.launch 配置文件。

如果您没有使用 webAppCreator,您可以手动运行 com.google.gwt.dev.DevMode 中的 main 类,该类位于 gwt-dev.jar 中。

重要:如果您没有使用生成的启动配置,请注意,GWT 开发模式使用 JVM 的类路径查找模块(以及因此的客户端 源代码)。请确保在类路径中首先添加您的源代码目录。

GWT 开发模式

注意:本节介绍了在没有 Google 插件 for Eclipse 的情况下使用开发模式.

GWT 开发模式窗口最初打开时有两个选项卡。第一个提供了一个界面来启动您的 GWT 模块,并记录了与特定模块无关的日志。

DevelopmentShell1

_(点击放大)_

提供应用程序

第二个选项卡显示来自嵌入式 Web 服务器的日志消息。默认情况下,开发模式运行一个内部 Jetty 实例来提供您的 Web 应用程序。此嵌入式 Jetty 实例直接从您的项目的 war 目录提供服务。

您可以通过将 -noserver 选项传递给开发模式来禁用此内部服务器,并改为运行您自己的外部服务器。请参阅常见问题解答“如何在开发模式下使用我自己的服务器,而不是 GWT 的内置服务器?”

启动浏览器

从 GWT 2.0 开始,开发模式使用常规浏览器,而不是嵌入式浏览器。您可以使用任何受支持的浏览器,包括其他机器上的浏览器,只要它安装了 GWT 开发者插件。如果您使用的是没有安装插件的浏览器,您将收到一条消息,并提供下载插件的选项。

浏览器通常会通过 -startupUrl 命令行选项自动打开(尽管如果您没有提供任何选项,GWT 会尝试查找可行的启动 URL)。要启动应用程序,请选择要使用的 URL,然后选择“启动默认浏览器”。GWT 使用许多启发式方法来确定使用哪个浏览器,但根据您的设置,它可能不会启动您想要的浏览器。在这种情况下,您可以选择“复制到剪贴板”,您需要启动的 URL 将被复制到系统剪贴板(并且还会显示在日志窗口中)。然后,您可以将此 URL 粘贴到安装了插件的任何浏览器中,或者您可以在另一台机器上的浏览器中键入 URL(在这种情况下,您必须根据需要更改 URL 中的主机名)。

HostedMode1

当模块在浏览器中加载时,您将看到一个新选项卡,其中包含特定浏览器中一个 URL 的日志。如果在一个页面上有多个模块,将有一个下拉框供您选择要显示哪个模块的日志。当您刷新页面时,会弹出一个会话下拉框,允许您选择要显示哪个会话的日志。

刷新开发模式

您不需要在修改源代码后重新启动开发模式。相反,在开发模式仍在运行的情况下,编辑客户端代码或资源,保存您的更改,然后在您的浏览器中刷新页面。刷新后,您的代码将使用更改重新编译,新版本将加载到浏览器中。刷新浏览器比关闭并重新启动开发模式要快得多。

您可能会注意到,有时您的更改即使您没有刷新浏览器也会生效。这种行为是开发模式与编译代码交互方式的结果,但它并不总是可靠的。具体来说,它只发生在您对现有函数进行微小更改并且 IDE 能够替换正在运行的代码时。为了确保您的更改已包含在内,请养成在更改后始终刷新浏览器的习惯。

重新加载服务器代码

类似地,“Jetty”选项卡中的“重新启动服务器”按钮允许您重新启动嵌入式 Jetty 服务器,而无需关闭并重新启动开发模式。当您对服务器端代码进行了配置或代码更改时,这很有用。所有服务器端类将从您的 war/WEB-INF/classeswar/WEB-INF/lib 文件夹中使用新代码重新加载。如果您在使用 RPC 时在开发模式下遇到 IncompatibleRemoteServiceException,请尝试重新启动服务器并刷新客户端。

在开发模式下生成调试消息:GWT.log()

调试消息显示在开发模式日志窗口中。其中一些消息来自 GWT。但是,您可以通过使用对GWT.log() 的调用来生成自己的调试消息。

例如,修改标准项目以在 ClickHandler 中发出调试消息,会导致每次用户单击按钮时都会在日志窗口中显示调试消息。

import com.google.gwt.core.client.GWT;

   ...

   button.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        GWT.log("User Pressed a button.", null); // Added debugging message
        if (label.getText().equals(""))
          label.setText("Hello World!");
        else
          label.setText("");
      }
    });

DevelopmentShell2

对 GWT.log() 的调用仅供调试应用程序时使用。它们在生产模式下被优化掉。例如,考虑以下对 onClick() 方法的更改,该更改旨在故意触发异常

public void onClick(Widget sender) {
        GWT.log("User pressed a button.", null);
        Object nullObject = null;
        nullObject.toString(); // Should cause NullPointerException

当应用程序遇到异常时,会在模块的日志窗口中打印一条消息。异常会用红色图标突出显示。在本例中,当您单击浏览器窗口中的按钮时,会触发 NullPointerException,异常的回溯信息会显示在日志区域下方的状态区域中。单击异常消息或图标会在下方的消息区域中显示异常的完整文本。

DevelopmentShell3

启用内部 GWT 调试消息

日志窗口可以显示更详细的调试信息,如果您通过指定 -logLevel 命令行参数来调用它。指定 SPAM 级别将打开 GWT 引擎内部的许多消息。这些消息以分层树的形式显示,可以通过单击各个行或使用工具栏中的“展开全部”和“折叠全部”图标来操作。

DevelopmentShell4

使用带有开发模式的 IDE

当使用 Eclipse、JBuilder 或 IntelliJ 等 IDE 时,可以使用 IDE 的内置 Java 调试器轻松地调试您的模块。只需在代码中设置一个断点(例如,onModuleLoad() 入口点),您希望调试器在此处停止并允许您检查程序的状态。有关使用 Eclipse IDE 在开发模式下进行调试的示例,请参阅入门教程,调试 GWT 应用程序

启动示例

让我们看看在开发模式下启动 GWT 应用程序时幕后发生的事情。要运行开发模式,您需要使用主类 com.google.gwt.dev.DevMode 启动一个 Java VM。如果您查看生成的 ant build.xml,您会发现类似以下内容

<target name="devmode" depends="javac" description="Run development mode">
  <java failonerror="true" fork="true" classname="com.google.gwt.dev.DevMode">
    <classpath>
      <pathelement location="src"/>
      <path refid="project.class.path"/>
    </classpath>
    <jvmarg value="-Xmx256M"/>
    <arg value="-startupUrl"/>
    <arg value="Hello.html"/>
    <!-- Additional arguments like -style PRETTY or -logLevel DEBUG -->
    <arg value="com.google.gwt.sample.hello.Hello"/>
  </java>
</target>

这类似于在命令行上运行以下命令

java -Xmx256M -cp "src;war/WEB-INF/classes;\gwt-2.0.0\gwt-user.jar;\gwt-2.0.0\gwt-dev.jar"
  com.google.gwt.dev.DevMode -startupUrl Hello.html com.google.gwt.sample.hello.Hello

-startupUrl 参数告诉开发模式哪个 URL 可用于启动。如果值不包含域,则假设域为 localhost。端口被假定为运行嵌入式服务器的端口。在上面的示例中,此地址为 https://127.0.0.1:8888/Hello.html(带有一个额外的参数,指定了开发模式代码服务器的位置)。

最后一个参数(没有前导标记的结尾参数)是我们关心的模块或模块集。此值是必需的,以便使用任何您可能想要运行的 GWT 模块的引导脚本正确初始化 war 目录。

生产模式和开发模式之间的语言差异

通常,如果您的代码在开发模式下按预期运行并编译成 JavaScript 且没有错误,则生产模式的行为将等效。偶尔不同的问题会导致生产模式中出现开发模式中不会出现的细微错误。幸运的是,这些情况很少见。

GWT 文档中提供了一个已知与语言相关的“陷阱”的完整列表

在开发模式下使用 EJB

GWT 为开发模式 shell 脚本提供了 -noserver 选项,用于处理此类问题。

-noserver 选项指示开发模式不要启动嵌入式 Jetty 实例。取而代之的是,您将运行您选择的 J2EE 容器,并将其用作嵌入式 Jetty 实例的替代。

在开发模式下使用我自己的服务器而不是 GWT 的内置 Jetty 实例

如果您不需要或不希望使用 GWT 开发模式中嵌入的 Jetty 实例来为您的 servlet 提供调试服务,您可以使用 -noserver 标志来阻止 Jetty 启动,同时仍然利用开发模式来调试您的 GWT 客户端代码。

如果您需要 -noserver 选项,可能是因为处理 XMLHTTPRequest 数据请求的服务器端代码需要更多内容,或者只是与 Jetty 不同的内容。以下是您可能需要使用 -noserver 的一些示例情况

  • 您需要一个 EJB 容器,嵌入式 Jetty 服务器不支持。
  • 您有广泛的 Servlet 配置(具有自定义 web.xml 和可能存在的 server.xml 文件),使用嵌入式 Jetty 非常不方便。
  • 您根本没有在服务器上使用 J2EE(例如,您可能正在使用 JSON 和 Python)。

当使用 -noserver 标志时,您的外部服务器将被 GWT 开发模式浏览器用来为您的动态内容和所有静态内容(例如,GWT 应用程序的主页、其他 HTML 文件、图像、CSS 等等)提供服务。这使您能够以最适合您的应用程序和基础设施的方式组织您的项目文件。

虽然您自己的外部服务器处理所有静态内容和动态资源,但所有浏览器应用程序逻辑继续在开发模式内部的 Java 中处理。这意味着您仍然可以在 Java 中像往常一样调试客户端代码,但所有服务器端请求将由您选择的 Web 或应用程序服务器提供服务。(如果您使用的是配置为与 GWT 的开发模式集成以进行调试的 IDE,例如 Eclipse,那么使用 -noserver 将阻止您在用于调试开发模式的相同调试器实例中自动调试服务器代码。但是,如果您使用的服务器软件支持它,您当然可以使用外部调试工具。)

以下是如何使用 -noserver 的分步说明

  1. 根据需要配置您的服务器;记下包含 GWT 应用程序主页面 的 URL。
  2. 将所有静态内容文件(例如,主 HTML 页面、图像、CSS 等)安排在服务器上,您喜欢的方式。
  3. 编辑您的开发模式执行脚本(例如,您的 Eclipse 运行配置或由 GWT webAppCreator 生成的 ant 开发构建目标),并添加或更新以下选项
    • 添加 -noserver 命令行参数。
    • 更改参数列表末尾的 URL,使其与您在步骤 #1 中记录的 URL 相匹配。
  4. 使用 ant 构建目标编译一次您的应用程序。理想情况下,您可以使用 GWT 的 -war 选项将输出文件直接生成到外部服务器的静态内容文件夹中。否则,您需要将 GWT 输出文件夹从 war/<moduleName> 复制到外部服务器的静态内容中。

小心不要省略步骤 #4 中的文件复制:这是一个您只需要执行一次的操作,但这是必要的步骤。但是,需要注意的一点是,如果您应用程序使用 GWT RPC,并且如果应用程序跨线序列化 的类型实现了 java.io.Serializable 接口,则您可能需要替换 .gwt.rpc 文件。如果这些类型发生更改,或者向 RPC 调用添加了新的可序列化类型,GWT 编译器将生成一个新的 .gwt.rpc 文件。您需要将部署在 Web 服务器上的旧文件替换为新生成的文件。但是,如果您的 Web 服务器将 GWT 编译器的 war 输出目录作为应用程序的 war 目录,则您不需要重新编译这些更改,并且开发模式将负责生成和正确放置 *.gwt.rpc 文件。

开发模式选项

您可以传递许多选项给开发模式进程,以控制您想要如何启动开发模式浏览器。这些选项可能因版本而异,但通常会包含以下命令行帮助文本中显示的选项

$ java -cp gwt-dev.jar com.google.gwt.dev.DevMode
Missing required argument 'module[s]'
Google Web Toolkit 2.12.0
DevMode [-[no]startServer] [-port port-number | "auto"] [-logdir directory] [-logLevel (ERROR|WARN|INFO|TRACE|DEBUG|SPAM|ALL)] [-gen dir] [-bindAddress host-name-or-address] [-codeServerPort port-number | "auto"] [-[no]superDevMode] [-server servletContainerLauncher[:args]] [-startupUrl url] [-war dir] [-deploy dir] [-extra dir] [-modulePathPrefix ] [-workDir dir] [-XmethodNameDisplayMode (NONE|ONLY_METHOD_NAME|ABBREVIATED|FULL)] [-sourceLevel [auto, 1.8, 9, 10, 11, 17]] [-[no]generateJsInteropExports] [-includeJsInteropExports/excludeJsInteropExports regex] [-[no]incremental] [-style (DETAILED|OBFUSCATED|PRETTY)] [-[no]failOnError] [-setProperty name=value,value...] module[s]

where
  -[no]startServer                                  Starts a servlet container serving the directory specified by the -war flag. (defaults to ON)
  -port                                             Specifies the TCP port for the embedded web server (defaults to 8888)
  -logdir                                           Logs to a file in the given directory, as well as graphically
  -logLevel                                         The level of logging detail: ERROR, WARN, INFO, TRACE, DEBUG, SPAM or ALL (defaults to INFO)
  -gen                                              Debugging: causes normally-transient generated types to be saved in the specified directory
  -bindAddress                                      Specifies the bind address for the code server and web server (defaults to 127.0.0.1)
  -codeServerPort                                   Specifies the TCP port for the code server (defaults to 9997 for classic Dev Mode or 9876 for Super Dev Mode)
  -[no]superDevMode                                 Runs Super Dev Mode instead of classic Development Mode. (defaults to ON)
  -server                                           Specify a different embedded web server to run (must implement ServletContainerLauncher)
  -startupUrl                                       Automatically launches the specified URL
  -war                                              The directory into which deployable output files will be written (defaults to 'war')
  -deploy                                           The directory into which deployable but not servable output files will be written (defaults to 'WEB-INF/deploy' under the -war directory/jar, and may be the same as the -extra directory/jar)
  -extra                                            The directory into which extra files, not intended for deployment, will be written
  -modulePathPrefix                                 The subdirectory inside the war dir where DevMode will create module directories. (defaults empty for top level)
  -workDir                                          The compiler's working directory for internal use (must be writeable; defaults to a system temp dir)
  -XmethodNameDisplayMode                           EXPERIMENTAL: Specifies method display name mode for chrome devtools: NONE, ONLY_METHOD_NAME, ABBREVIATED or FULL (defaults to NONE)
  -sourceLevel                                      Specifies Java source level (defaults to 1.8)
  -[no]generateJsInteropExports                     Generate exports for JsInterop purposes. If no -includeJsInteropExport/-excludeJsInteropExport provided, generates all exports. (defaults to OFF)
  -includeJsInteropExports/excludeJsInteropExports  Include/exclude members and classes while generating JsInterop exports. Flag could be set multiple times to expand the pattern. (The flag has only effect if exporting is enabled via -generateJsInteropExports)
  -[no]incremental                                  Compiles faster by reusing data from the previous compile. (defaults to ON)
  -style                                            Script output style: DETAILED, OBFUSCATED or PRETTY (defaults to OBFUSCATED)
  -[no]failOnError                                  Fail compilation if any input file contains an error. (defaults to OFF)
  -setProperty                                      Set the values of a property in the form of propertyName=value1[,value2...].
and
  module[s]                                         Specifies the name(s) of the module(s) to host

任何时候您想查找 GWT 版本可用的开发模式选项,您都可以像上面所示的那样从命令行调用 DevMode 类,它将列出可用的选项及其描述。(从包含 gwt-dev.jar 的目录运行命令,或在该文件之前添加路径:-cp _path_/gwt-dev.jar。)

超级开发模式

早期采用者可能希望尝试使用开发模式的替代方案。请参阅 介绍超级开发模式

在生产模式下运行

在您的应用程序在开发模式下运行良好后,您将希望在目标 Web 浏览器中试用您的应用程序;也就是说,您想要在生产模式下运行它。

在生产模式下运行您的应用程序使您能够测试已部署的应用程序。如果您在 web.xml 文件中指定了 servlet 组件,您的 GWT RPC 调用也将被提供给浏览器。您还可以使用不同的浏览器或在另一台机器上运行的浏览器,并将其指向相同的 URL(在 URL 中将您的工作站的主机名或 IP 地址替换为 localhost)。

在生产模式下运行是测试以下内容的好方法

您的应用程序的性能
开发模式使用特殊的引擎将您的应用程序作为 Java 字节码和原生 JavaScript 的混合来运行。如果您的代码在 Java 和 JavaScript 之间进行了大量来回调用,那么您的代码在开发模式下的运行速度可能比在生产模式下的运行速度慢。这对于 UI 代码尤其如此。另一方面,密集的算法纯 Java 代码在开发模式下的运行速度往往更快,因为 JVM 的性能优于大多数 JavaScript 引擎。如果您的应用程序显示大量数据或具有大量小部件,您将需要确认应用程序最终部署后性能是否可以接受。
您的应用程序在不同浏览器上的外观
因为 GWT 小部件使用浏览器的原生 DOM 组件,所以您的应用程序的外观可能会因浏览器而异。更重要的是,如果您正在使用样式表,您将需要仔细检查每个浏览器上的应用程序。
您的应用程序逻辑在不同浏览器上的执行方式
GWT 的设计目的是提供跨浏览器支持,以便一般的 GWT 开发人员不必担心跨浏览器支持。但是,如果您是小部件作者,或者如果您正在使用第三方 JavaScript 库,您需要确认这些组件在您计划支持的每个目标浏览器上都正常工作。

了解 GWT 编译器

GWT 的核心是一个编译器,它将 Java 源代码转换为 JavaScript,将您的工作 Java 应用程序转换为等效的 JavaScript 应用程序。

GWT 编译器支持绝大多数 Java 语言。 GWT 运行时库 模拟了 Java 运行时库的相关子集。如果 JRE 类或方法不受支持,编译器将发出错误。

您可以通过以下方式之一使用要编译的模块的名称运行编译器

  • 使用命令行中的 java 运行主类 com.google.gwt.dev.Compiler
  • 如果您使用 webAppCreator 脚本创建了项目,则可以使用 Ant 运行生成的 build.xml
  • 如果您使用的是 Google Plugin for Eclipse,则可以通过单击 GWT Compile Project 按钮 icon 来编译您的应用程序。

编译成功完成后,将创建包含项目 JavaScript 实现的目录。编译器将为它编译的每个模块创建一个目录。

C:\gwt-2.6.1\samples\Hello>ant
Buildfile: build.xml

libs:

javac:

gwtc:
     [java] Compiling module com.google.gwt.sample.hello.Hello
     [java]    Compiling 5 permutations
     [java]       Permutation compile succeeded
     [java]    Linking into war
     [java]       Link succeeded
     [java]    Compilation succeeded -- 20.313s

build:

BUILD SUCCESSFUL
Total time: 22 seconds

运行 GWT 编译器后,您的 war 目录应该如下所示

C:\gwt-2.6.1\samples\Hello>\bin\find war
war
war\hello
war\hello\18EEC2DA45CB5F0C2050E2539AE61FCE.cache.html
war\hello\813B962DC4C22396EA14405DDEF020EE.cache.html
war\hello\86DA1DCEF4F40731BE71E7978CD4776A.cache.html
war\hello\A37FC20FF4D8F11605B2C4C53AF20B6F.cache.html
war\hello\E3C1ABB32E39A126A9194DB727F7742A.cache.html
war\hello\14A43CD7E24B0A0136C2B8B20D6DF3C0.cache.png
war\hello\548CDF11D6FE9011F3447CA200D7FB7F.cache.png
war\hello\9DA92932034707C17CFF15F95086D53F.cache.png
war\hello\A7CD51F9E5A7DED5F85AD1D82BA67A8A.cache.png
war\hello\B8517E9C2E38AA39AB7C0051564224D3.cache.png
war\hello\clear.cache.gif
war\hello\hello.nocache.js
war\hello\hosted.html
war\Hello.html

在上面的示例中,war/hello/hello.nocache.js 是您将在主机 HTML 页面中包含的脚本,以加载 Hello 应用程序。在本例中,主机 HTML 页面位于 war/Hello.html,并通过相对 URL hello/hello.nocache.js 加载 GWT 启动脚本。

您可能已经注意到,build.xml 文件中由 webAppCreator 生成的编译目标将 war 输出目录用作输入和输出源。情况不必如此,您可以轻松地将 war 目录配置为仅作为输出目录,同时通过添加构建目标来将静态资源从源目录复制到最终的输出目录,从而使用其他目录作为源目录路径。有关更多详细信息,请参阅此war 目录常见问题解答

您可能已经注意到,除了 GWT 编译器输出之外,还会生成许多其他文件。其中有一些文件是 部署您的应用程序 的关键。

关键应用程序文件

运行 GWT 编译器后,您将在 WAR(或 Web 存档)文件夹中找到输出,其结构如下

img

如果您在 1.6 版本之前使用过 GWT,那么 war/hello 目录中的文件您应该很熟悉。唯一的区别是这些文件现在生成的位置,以及 主机 HTML 页面 和 CSS 文件不再与其他 .cache.html/png 文件位于同一目录中。这些文件生成的路径由 GWT 模块 XML 文件控制。这些是您在 Web 服务器上部署 GWT 应用程序的关键应用程序文件。

主机 HTML 页面

当客户浏览您的应用程序时,主机 HTML 页面 是他们应该访问的第一个页面,也是加载其余应用程序文件的位置。要加载您的应用程序,主机 HTML 页面必须包含一个引用您的 GWT 应用程序引导文件的 <script> 标签(如下所述)。您通常还会包含一个引用应用程序 CSS 文件的 <link> 标签,除非您通过将 <stylesheet> 标签添加到模块 XML 文件中直接注入样式表。

您也可以从网站中的任何其他位置加载脚本,但默认的起始页面通常是开发人员用来加载 GWT 应用程序的入口点。上面提到的 Hello 启动器示例应用程序中的主机页面如下所示。

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel="stylesheet" href="Hello.css">
    <title></title>
  </head>
  <body>

<script type="text/javascript" language='javascript' src='hello/hello.nocache.js'></script>
    <!-- Along with page title and table headers defined -->
  </body>
</html>
引导文件

您可能已经注意到,其中一个生成的文件以您的模块命名,后跟 .nocache.js 后缀。这是 GWT 引导文件。类似于输出子目录 war/<app_name>,此文件的名称也由模块 XML 文件中的 rename-to 属性控制。此文件负责根据客户端的浏览器和区域设置(或任何其他自定义选择规则,请参见 延迟绑定)选择要加载的应用程序的正确版本。与每个浏览器/区域设置兼容的应用程序的各种版本是 <md5>.cache.html 应用程序文件(如下所述)。

主机 HTML 页面引用此文件,以便访问您的页面的客户端首先下载引导程序,而引导程序脚本反过来会确定它正在运行的浏览器环境,并确定要加载的应用程序的适当版本。有关引导过程的更多详细信息,请参见 文档

应用程序文件

war/<app_name> 目录中生成的 <md5>.cache.html 文件以及引导脚本是生成的文件集中最重要的部分。它们代表一个针对特定浏览器(或区域设置)定制的应用程序版本。这些是引导脚本在确定正在运行的浏览器后选择的应用程序文件。

另一个生成的应用程序文件,它不是严格意义上部署 GWT 应用程序所必需的,但如果您使用 GWT RPC 和通过 RPC 传输的类型的 Serializable 接口支持,则需要该文件,即 <md5>.gwt.rpc 文件。序列化策略文件必须可通过您的 RPC RemoteServiceServlet 通过 ServletContext.getResource() 调用访问。

公共资源

所有公共资源,例如图像文件、样式表或 XML 文件,可以在开发期间放置在 war 目录或其任何子目录下的任何位置。只要 GWT 应用程序代码中对这些资源的引用在部署时仍然有效,您就可以预期您的应用程序在生产中正常运行。在 GWT 1.6 及更高版本中,<public> 标签仍然得到支持,因此您可以将公共资源放置在公共目录中(如模块 XML 文件中所定义),这些资源将被复制到 war/<app_name> 文件夹中。但是,最佳实践是将公共资源放置在 war 目录中,并从该位置使用它们。这符合标准的 Servlet 2.5 API 规范,并且如果您计划在 servlet 容器上部署应用程序,这将使部署变得更容易。

如果您在应用程序中使用 ClientBundle,则生成的捆绑包将在编译后放置在 war/<app_name> 目录中。

完美缓存

除了其他优化和性能改进技术之外,GWT 还提供“完美缓存”的概念,如果您正确部署应用程序,您可以利用它。

您可能已经注意到,引导脚本文件名包含 .nocache.js 后缀,而其余的 GWT 应用程序文件包含 .cache.html 后缀。这些旨在作为指示器,您可以使用它们来配置您的 Web 服务器以实现完美缓存。引导脚本以一个众所周知的应用程序名称(<app_name>.nocache.js)命名,而 GWT 应用程序文件在其名称中都包含 md5 校验和。这些 md5 校验和是在编译时从您的 GWT 代码库中计算出来的。引导脚本包含一个查找表,当您的客户端第一次访问您的网站并加载您的 GWT 应用程序时,该表会选择正确的 <md5>.cache.html 文件。引导过程将在 此处 详细说明。

应用程序文件名将在您的代码库更改时始终更改这一事实意味着您的客户端可以安全地缓存这些资源,并且不需要在每次访问您的网站时都重新获取 GWT 应用程序文件。不应该完全缓存的资源(足够进行 If-Modified-Since 获取并节省带宽)是引导脚本,因为它包含查找正确应用程序文件所需的逻辑。如果您要在 Apache HTTP 服务器上配置这些规则,您可能会在您的 .htaccess 配置文件中获得如下内容,同时使用 mod_expires 和 mod_headers

<Files *.nocache.*>
  ExpiresActive on
  ExpiresDefault "now"
  Header merge Cache-Control "public, max-age=0, must-revalidate"
</Files>

<Files *.cache.*>
  ExpiresActive on
  ExpiresDefault "now plus 1 year"
</Files>

GWT 编译器选项

您可以向 GWT 编译器进程传递许多选项来控制您希望如何编译 GWT 应用程序以及希望将输出生成到哪里。这些选项在不同版本之间可能略有不同,但通常会包括下面命令行帮助文本中显示的选项

> java -cp gwt-dev.jar com.google.gwt.dev.Compiler
Missing required argument 'module[s]'
Google Web Toolkit 2.12.0
Compiler [-logLevel (ERROR|WARN|INFO|TRACE|DEBUG|SPAM|ALL)] [-workDir dir] [-X[no]closureFormattedOutput] [-[no]compileReport] [-X[no]checkCasts] [-X[no]classMetadata] [-[no]draftCompile] [-[no]checkAssertions] [-XfragmentCount numFragments] [-gen dir] [-[no]generateJsInteropExports] [-includeJsInteropExports/excludeJsInteropExports regex] [-XmethodNameDisplayMode (NONE|ONLY_METHOD_NAME|ABBREVIATED|FULL)] [-Xnamespace (NONE|PACKAGE)] [-optimize level] [-[no]saveSource] [-setProperty name=value,value...] [-style (DETAILED|OBFUSCATED|PRETTY)] [-[no]failOnError] [-[no]validateOnly] [-sourceLevel [auto, 1.8, 9, 10, 11, 17]] [-localWorkers count] [-[no]incremental] [-war dir] [-deploy dir] [-extra dir] [-saveSourceOutput dir] module[s]

where
  -logLevel                                         The level of logging detail: ERROR, WARN, INFO, TRACE, DEBUG, SPAM or ALL (defaults to INFO)
  -workDir                                          The compiler's working directory for internal use (must be writeable; defaults to a system temp dir)
  -X[no]closureFormattedOutput                      EXPERIMENTAL: Enables Javascript output suitable for post-compilation by Closure Compiler (defaults to OFF)
  -[no]compileReport                                Compile a report that tells the "Story of Your Compile". (defaults to OFF)
  -X[no]checkCasts                                  EXPERIMENTAL: DEPRECATED: use jre.checks.checkLevel instead. (defaults to OFF)
  -X[no]classMetadata                               EXPERIMENTAL: Include metadata for some java.lang.Class methods (e.g. getName()). (defaults to ON)
  -[no]draftCompile                                 Compile quickly with minimal optimizations. (defaults to OFF)
  -[no]checkAssertions                              Include assert statements in compiled output. (defaults to OFF)
  -XfragmentCount                                   EXPERIMENTAL: Limits of number of fragments using a code splitter that merges split points.
  -gen                                              Debugging: causes normally-transient generated types to be saved in the specified directory
  -[no]generateJsInteropExports                     Generate exports for JsInterop purposes. If no -includeJsInteropExport/-excludeJsInteropExport provided, generates all exports. (defaults to OFF)
  -includeJsInteropExports/excludeJsInteropExports  Include/exclude members and classes while generating JsInterop exports. Flag could be set multiple times to expand the pattern. (The flag has only effect if exporting is enabled via -generateJsInteropExports)
  -XmethodNameDisplayMode                           EXPERIMENTAL: Specifies method display name mode for chrome devtools: NONE, ONLY_METHOD_NAME, ABBREVIATED or FULL (defaults to NONE)
  -Xnamespace                                       Puts most JavaScript globals into namespaces. Default: PACKAGE for -draftCompile, otherwise NONE
  -optimize                                         Sets the optimization level used by the compiler.  0=none 9=maximum.
  -[no]saveSource                                   Enables saving source code needed by debuggers. Also see -debugDir. (defaults to OFF)
  -setProperty                                      Set the values of a property in the form of propertyName=value1[,value2...].
  -style                                            Script output style: DETAILED, OBFUSCATED or PRETTY (defaults to OBFUSCATED)
  -[no]failOnError                                  Fail compilation if any input file contains an error. (defaults to OFF)
  -[no]validateOnly                                 Validate all source code, but do not compile. (defaults to OFF)
  -sourceLevel                                      Specifies Java source level (defaults to 1.8)
  -localWorkers                                     The number of local workers to use when compiling permutations
  -[no]incremental                                  Compiles faster by reusing data from the previous compile. (defaults to OFF)
  -war                                              The directory into which deployable output files will be written (defaults to 'war')
  -deploy                                           The directory into which deployable but not servable output files will be written (defaults to 'WEB-INF/deploy' under the -war directory/jar, and may be the same as the -extra directory/jar)
  -extra                                            The directory into which extra files, not intended for deployment, will be written
  -saveSourceOutput                                 Overrides where source files useful to debuggers will be written. Default: saved with extras.
and
  module[s]                                         Specifies the name(s) of the module(s) to compile

无论何时您要查找适用于您 GWT 版本的 GWT 编译器选项,您都可以简单地从命令行调用 Compiler 类(如上所示),它将列出可用的选项及其描述。(从包含 gwt-dev.jar 的目录运行命令,或在该文件之前添加路径:-cp _path_/gwt-dev.jar。)