由于几个原因,我有兴趣编写一个混合应用程序,该应用程序部分用Java编码(通过Google Web Toolkit)并部分用JavaScript编码。我打算使用GWT Exporter从JavaScript调用Java库。
麻烦的是,这会破坏很多代码优化和压缩的机会。 GWT主要用于优化它生成的JavaScript,第三方Javascript压缩库在给定GWT输出时可能会崩溃。
有没有办法告诉GWT编译器“嘿,将这些Javascript文件传递到优化传递中”? GWT有一个标志,用于在引擎盖下使用Closure Compiler(显然支持优化常规javascript),所以感觉这应该是可能的。
答案 0 :(得分:0)
只要您可以要求Closure编译源代码,就有可能,但您必须得到其他'其他'将源代码转换为GWT(以及后来的闭包)正在编译的代码。目前,这意味着将该代码放在JSNI中,否则它只是文件系统上的另一个文件,并且编译器无法知道进出的依赖性,因为它同样不能告诉您何时/如何正在加载该文件。
如果我没记错的话,Closure中依赖项的标准用法是通过文件顶部的JavaScript中的goog.require()
方法调用 - 这两者都声明了依赖关系,如果需要,则加载文件。如果没有这个,你的基本HTML页面需要为你可能使用的每个文件都有<script>
个标签,而且实际上没有运行那个页面,Closure不知道这些文件要加载的顺序,或者如何在编译源代码时要远远地运行。
GWT本身(即在Closure之外)只对Java源代码中作为JSNI包含的原始JS进行了一小组优化:
com.google.gwt.dev.js.JsStaticEval
- 简单的常量折叠和其他表达式简化com.google.gwt.dev.js.JsInliner
- 特定复杂度阈值下的内联函数和其他各种清理com.google.gwt.dev.js.JsUnusedFunctionRemover
- 对未引用的函数/变量的简单修剪com.google.gwt.dev.js.JsDuplicateCaseFolder
- 在多个case
块中查找相同的正文,并将其合并为一个直通案例。 GWT有三种主要方式来包含JS源:JSNI,.gwt.xml中的标记(不是所有链接器都支持)和com.google.gwt.core.client.ScriptInjector
来从字符串常量或远程URL中提取。只有第一个将代码视为实际源代码 - 第二个/第三个代码来自任何源代码,并且不依赖编译时静态可用的代码。 JSNI有其自身的局限性 - 它不支持with
块,并且必须使用$wnd
和$doc
来引用主机页面window
和document
。
答案 1 :(得分:0)
首先,虽然这不是您的问题,但您必须注意,要使用gwt-exporter,您必须为每个要填充的类调用GWT.create
,或者调用exportAll()
方法导出标记为可导出的所有内容。这意味着你要对编译器说你将使用这些类,即使你的JS应用程序最终也不会使用它们。所以你不会利用删除未使用的代码导致大的js输出。您可以使用代码拆分来分割碎片中的单独代码。
其次,与你的问题有关,正如@Colin在他的回答中所说,只有编写在JSNI块中的代码才会被GWT编译器优化,但默认优化非常简单,尽管如果使用闭包编译器它是一个有点强。我没有尝试过,但我认为不允许关闭注释,因为GWT编译器可能会在将js传递给闭包编译器之前删除它们。
无论如何,将这些文件包含在JSNI块中的主要问题是,您必须手动将代码复制并粘贴到java类中,然后执行其他一些技巧来解决$ wnd等问题。
我们在gwt-query中有一个JsniBundle生成器能够从文件系统或任何url中获取.js
个文件,并且在编译时包含JSNI片段中的代码并制作一些技巧它在GWT运行的iframe
中工作。它适用于我使用的几乎库和插件,但有时我不得不修改javascript源以允许打沙它。
这里有一个如何包含jquery和highcharts的例子:
public interface JQueryBundle extends JsniBundle {
@LibrarySource(value =
"http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js")
public void initJQuery();
}
public static abstract class HighCharts implements JsniBundle {
@LibrarySource("js/highcharts.src.js")
public abstract void initHighcharts();
public void drawChart(String id, JavaScriptObject props) {
JavaScriptObject $container = JsUtils.runJavascriptFunction(window, "$", "#" + id);
JsUtils.runJavascriptFunction($container, "highcharts", props);
}
}
public void testHighCharts() {
JQueryBundle jQuery = GWT.create(JQueryBundle.class);
HighCharts highCharts = GWT.create(HighCharts.class);
jQuery.initJQuery();
highCharts.initHighcharts();
highCharts.drawChart("chart", charData);
}
使用此方法的一些优点在我们的GWT.create-2013演示文稿的this slide中列举。
答案 2 :(得分:0)
您可以使用GWT编译器优化任意JavaScript代码,只需使用适当命名的LinkerContext.optimizeJavaScript(TreeLogger, String)
方法。 LinkerContext对象在Linkers中可用,它们是在编译期间运行的自定义代码片段。这是关于如何编写一个的最小例子:
@LinkerOrder(LinkerOrder.Order.POST)
public class ScriptOptimizer extends AbstractLinker {
@Override
public String getDescription() {
return "Optimizes external JavaScript files.";
}
@Override
public ArtifactSet link(TreeLogger logger, LinkerContext context,
ArtifactSet artifacts) throws UnableToCompleteException {
// This is some arbitrary JavaScript code you'd probably want to read
// from a static file in your classpath
String script = "var foobar = 1; for (var i = foobar; i < 5; i++) alert(1);";
// Do the optimizations
script = context.optimizeJavaScript(logger, script);
// Create an Artifact from the optimized JavaScript string
ArtifactSet newArtifacts = new ArtifactSet(artifacts);
newArtifacts.add(emitString(logger, script, "example.js"));
return newArtifacts;
}
}
然后,要在GWT编译过程中包含链接器,请将其添加到* .gwt.xml:
<define-linker name="scriptoptimizer"
class="com.example.ScriptOptimizer" />
<add-linker name="scriptoptimizer" />
结果将是一个名为example.js
的编译文件。您当然可以根据需要生成任意数量的文件,或者为了获得最佳结果,将所有脚本连接成一个并将其编译为单个输出文件。