Home / TeaVM Patterns and Pitfalls     frequal.com

Add JavaScript platform to jpackage: Draft 1

Summary

jpackage already allows packaging Java applications for several platforms. This proposal adds a new platform: JavaScript.

This effort will enable jpackage to convert bytecode from the provided classes into JavaScript, and generate the required HTML to invoke the specified main method when opened in a web browser. These files will be bundled into a WAR file for easy deployment.

Goals

Non-Goals

Motivation

Java was once used to create client-side web applications via applets that could be launched by visiting a web page. Applets could draw on an area of the screen (like HTML5 Canvas) or manipulate the page DOM to create dynamic front-end applications (like JS single-page apps).

However, as evident in JEP 398 (https://openjdk.java.net/jeps/398), applets are no longer feasible due to the actions of browser vendors. While browsers have lost the ability to execute Java bytecode or invoke methods from the Java class libraries, they do have mature engines for executing a different sort of code (JavaScript) and an extensive list of useful APIs. By converting class files to JavaScript, and providing mechanisms to invoke browser APIs, Java can again be used to create in-browser applications. TeaVM has demonstrated that this is feasible and has numerous benefits:

Details

An additional jpackage option for type will be added: js

jpackage will use a JavaScript AOT compiler (TeaVM) to convert the Java code to JavaScript, with the main class compiled to a JavaScript method called 'main()'.

jpackage bundles application code, runtime, and resources into a platform-specific format. For this new JavaScript type, the layout will be either a ZIP file or a standard WAR file. The ZIP format will contain the files ready to be extracted to a static file webserver or HTML hosting service. Generated WARs will have the required structure to be deployable in a Java web application container.

WAR layout

ZIP Layout

Basic usage: Non-modular applications

Command-line usage is similar to jpackage today, except you use the --type js. For example, if you have your application JARs in a folder called lib and the JAR with the declared main() method is main.jar, you could use this command:
$ jpackage --type js --name myapp --input lib --main-jar main.jar
This will produce myapp.war in the current directory. This is a standard WAR file ready for deployment in any web application container (like Tomcat). When myapp/index.html is opened in a browser, the code in main() will be executed, in-browser. A typical Hello World main() method like
  public static void main(String args[]) {
    System.out.println("Hello, Browser!");
  }
will print the message on the browser developer console.

Processing

Conversion of the input JAR files to the classes.js file will be done by TeaVM. It will

js-specific options

  1. --minify: Perform a minification pass after generating JavaScript, renaming classes and methods to short, generated names to reduce download sizes and provide some obfuscation.
  2. --debug: Enable generation of source maps.
  3. --debug-full: Enable generation of source maps and bundled source files.
  4. --optimization: Choose simple, advanced, or full.
    • simple: Perform only basic optimizations
    • advanced: Perform more optimizations. Recommended for production.
    • full: Perform aggressive optimizations. Increases compilation time.
  5. --timezone-support: Enables timezone support, at the cost of increased application size
  6. --locale-list: Add extra locales via a list, at the cost of increased application size. Format: comma-separated list of locale IDs like "en_US, ru_RU"

Unsupported options for the JavaScript type

These options are unsupported for --type js

Caveats

Certain Java classes are not feasible to implement in a browser setting. Socket, for example, is not useful in a browser since JavaScript cannot open arbitrary socket connections. Code using unavailable classes will fail during packaging time with warnings about the missing classes.

Testing

Since TeaVM is Java-based, tests will be able to run on any platform.

Testing will focus on the new jpackage code and added functionality. Tests will confirm that when valid parameters are provided, that output is generated with the right name and in the right folder. Contents of the generated ZIP and WAR files will be checked for the presence of expected files. Testing generated files in a browser will be done manually.

A thorough test of TeaVM itself is out of scope for the jpackage testing. This is in line with jpackage testing for other platforms, in which the external packaging tool (like Wix on Windows) isn't exhaustively tested.

Dependencies

The jpackage js type will require TeaVM binaries to be present.

Implementation options:

High-Level Design

A new bundler will be added to the jpackage Java source code.

It will first ensure that TeaVM binaries (JAR files) are available locally, as described in the section above.

The new bundler will use TeaVM's TeaVMRunner (https://github.com/konsoletyper/teavm/blob/master/tools/cli/src/main/java/org/teavm/cli/TeaVMRunner.java), which conveniently accepts options similar to jpackage itself. TeaVMRunner will do the heavy lifting of converting the application JAR files and resources into classes.js.

The bundler will provide additional files required to make a web application, including an index.html to launch the main() method. The bundler will create the final archive (ZIP or WAR) using Java's ZipOutputStream. For the WAR format, the bundler will also add web.xml and MANIFEST.MF if not present to create a deployable, standard WAR file.


Last modified on 24 Apr 2021 by AO

Copyright © 2024 Andrew Oliver