Skip to content

Commit

Permalink
Handle static resources and externs (#117)
Browse files Browse the repository at this point in the history
This establishes a simple set of conventions for static resources and
externs. While encouraged, this new convention for externs is not enforced
or warned yet.

See discussion #116
Fixes #39
  • Loading branch information
niloc132 authored Feb 24, 2022
1 parent 45be16e commit 9cd821f
Show file tree
Hide file tree
Showing 16 changed files with 335 additions and 37 deletions.
29 changes: 18 additions & 11 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
J2CL Maven plugin
=================

This plugin includes the code original developed as
This plugins compiles Java sources to optimized JavaScript using https://github.com/google/j2cl/ and
https://github.com/google/closure-compiler/. All Java code in this project will be transpiled to JS,
and any source in dependencies will be transpiled as well, and all of that JS will then be optimized
with the closure-compiler to produce small, efficient JavaScript.

com.vertispan.j2cl:build-tools
Webjars that are included in the project's list of runtime dependencies will be made available in the
compile output, placed relative to the initial script's output directory.

built from here:
Resources present in a `public/` directory within normal Java packages will also be copied to the
output directory.

https://github.com/gitgabrio/j2cl-devmode-strawman

------------------------
All other JS found in Java packages will be assumed to be JavaScript that should be included in the
main build output, and is assumed to be safe to compile with closure.

# Example usage

Expand All @@ -23,20 +27,23 @@ tests](j2cl-maven-plugin/src/it/) used to verify various aspects of the project

The plugin has four goals

1. `build`: executes a single compilation, typically to produce a JS application or library.
1. `build`: executes a single compilation, typically to produce a JS application or library. Bound by
default to the `prepare-package` phase.

2. `test`: compiles and executes j2cl-annotated tests, once.
2. `test`: compiles and executes j2cl-annotated tests. Bound by default to the `test` phase.

3. `watch`: monitor source directories, and when changes happen that affect any `build` or `test`, recompile the
required parts of the project. Tests are not (presently) run, but can be run manually by loading the html pages
that exist for them.
required parts of the project. While this can be run on an individual client project, it is designed to run
on an entire reactor at once from the parent project, where it will notice changes from any project required by
the actual client projects, and can be directed to generate output anywhere that the server will notice and
serve it.

<!-- * `watch-test`: only rebuild things that affect `test` executions, useful when iterating on tests and avoiding
building the application itself
* `watch-build`: only rebuild things that affect `build` executions, may save time if tests aren't currently
being re-run -->

4. `clean`: cleans up all the plugin-specific directories
4. `clean`: cleans up all the plugin-specific directories.


----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ public interface Input {
*
* Specifies that only part of this input is required. A path entry that matches any
* of the provided filters will be included.
*
* The path parameter given to the matcher will be the relative path of the file within
* this input - the parent path will not be provided.
*/
Input filter(PathMatcher... filters);

Expand Down
87 changes: 87 additions & 0 deletions j2cl-maven-plugin/src/it/static-resources/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>static-resources</groupId>
<artifactId>static-resources</artifactId>
<version>1.0</version>

<properties>
<elemental2.version>1.1.0</elemental2.version>
</properties>

<dependencies>
<dependency>
<groupId>com.google.elemental2</groupId>
<artifactId>elemental2-core</artifactId>
<version>${elemental2.version}</version>
</dependency>
<dependency>
<groupId>com.google.elemental2</groupId>
<artifactId>elemental2-dom</artifactId>
<version>${elemental2.version}</version>
</dependency>
<dependency>
<groupId>com.google.elemental2</groupId>
<artifactId>elemental2-promise</artifactId>
<version>${elemental2.version}</version>
</dependency>

<dependency>
<groupId>com.vertispan.j2cl</groupId>
<artifactId>junit-annotations</artifactId>
<version>@j2cl.version@</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vertispan.j2cl</groupId>
<artifactId>junit-emul</artifactId>
<version>@j2cl.version@</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vertispan.j2cl</groupId>
<artifactId>junit-emul</artifactId>
<version>@j2cl.version@</version>
<classifier>sources</classifier>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<goals>
<goal>build</goal>
<!-- Tests have to be run by hand for now, htmlunit doesnt support fetch -->
<!--<goal>test</goal>-->
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>google-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/google-snapshots/</url>
</repository>
</repositories>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example;

import elemental2.dom.DomGlobal;
import elemental2.dom.Response;
import elemental2.promise.Promise;
import jsinterop.base.Js;
import jsinterop.annotations.JsType;

@JsType
public class App {
public static void main() {
getData("publicfile.js").then(data -> alert(data), err -> alert("fail!"));
getData("metainfresourcesfile.js").then(data -> alert(data), err -> alert("fail!"));
getData("ignoredfile.js").then(data -> alert("fail!"), err -> alert("success, file missing"));
}
private static Promise<Object> alert(Object data) {
DomGlobal.alert(data);
return Promise.resolve(data);
}
public static Promise<String> getData(String path) {
return DomGlobal.fetch(path)
.then(response -> {
if (response.ok) {
return response.text();
}
return Promise.reject(response.status + "");
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
setTimeout(function() {
App.main();
}, 0);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script type="application/javascript" src="static-resources.js"></script>
<title>static resources test</title>
</head>
<body>this is stored in the public/ directory, so it is in the same dir as the output js in the webappDirectory</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
com/example/public
" this file fails to parse, but that's okay, it will not be loaded as js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
" Deliberate parse error, if this file is seen by closure it will fail
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
META-INF/resources
" this file fails to parse, but that's okay, it will not be loaded as js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example;

import com.google.j2cl.junit.apt.J2clTestInput;

import elemental2.promise.Promise;

import org.junit.Assert;
import org.junit.Test;

/**
* Test has to be run by hand, htmlunit doesn't support fetch:
* https://github.com/HtmlUnit/htmlunit/issues/78
*/
@J2clTestInput(AppTest.class)
public class AppTest {
@Test(timeout = 1000)
public Promise<?> testPublicFile() {
return App.getData("publicfile.js");
}
@Test(timeout = 1000)
public Promise<?> testMetaInfFile() {
return App.getData("metainfresourcesfile.js");
}
@Test(timeout = 1000)
public Promise<?> testIgnoredFile() {
// failure expected, we handle that in the .then() so that the test will only see success
return App.getData("ignoredfile.js").then(text -> Promise.reject("failure expected"), fail -> {
if ("404".equals(fail)) {
return Promise.resolve("Succcess, saw 404");
}
return Promise.reject("Expected 404, saw " + fail);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.vertispan.j2cl.build.provided.ClosureTask.COPIED_OUTPUT;
import static com.vertispan.j2cl.build.provided.ClosureTask.copiedOutputPath;
import static com.vertispan.j2cl.build.provided.JsZipBundleTask.JSZIP_BUNDLE_OUTPUT_TYPE;

@AutoService(TaskFactory.class)
public class BundleJarTask extends TaskFactory {

Expand Down Expand Up @@ -67,11 +71,20 @@ public Task resolve(Project project, Config config) {
}

//cheaty, but lets us cache
Input jszip = input(project, "jszipbundle");
Input jszip = input(project, JSZIP_BUNDLE_OUTPUT_TYPE);

File initialScriptFile = config.getWebappDirectory().resolve(config.getInitialScriptFilename()).toFile();
Map<String, Object> defines = new LinkedHashMap<>(config.getDefines());

List<Input> outputToCopy = Stream.concat(
Stream.of(project),
scope(project.getDependencies(), Dependency.Scope.RUNTIME).stream()
)
// Only need to consider the original inputs and generated sources,
// J2CL won't contribute this kind of sources
.map(p -> input(p, OutputTypes.BYTECODE).filter(COPIED_OUTPUT))
.collect(Collectors.toList());

return new FinalOutputTask() {
@Override
public void execute(TaskContext context) throws Exception {
Expand Down Expand Up @@ -124,6 +137,11 @@ public void finish(TaskContext taskContext) throws IOException {
} catch (IOException e) {
throw new UncheckedIOException("Failed to write html import file", e);
}
for (Input input : outputToCopy) {
for (CachedPath entry : input.getFilesAndHashes()) {
copiedOutputPath(initialScriptFile.getParentFile().toPath(), entry);
}
}
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ public Task resolve(Project project, Config config) {
Input existingUnpackedBytecode = input(project, OutputTypes.INPUT_SOURCES);
return context -> {
for (CachedPath entry : existingUnpackedBytecode.getFilesAndHashes()) {
Files.createDirectories(context.outputPath().resolve(entry.getSourcePath()).getParent());
Files.copy(entry.getAbsolutePath(), context.outputPath().resolve(entry.getSourcePath()));
Path outputFile = context.outputPath().resolve(entry.getSourcePath());
Files.createDirectories(outputFile.getParent());
Files.copy(entry.getAbsolutePath(), outputFile);
}
};
}
Expand Down
Loading

0 comments on commit 9cd821f

Please sign in to comment.