TeaVM — a tool for creating web-frontend in Java, Kotlin and Scala
Quite a while ago I published habré article, where he spoke about his project, TeaVM. Since then a lot has happened with him, including one important thing, about which will be discussed below and for which I have decided to write on Habr. But first briefly remind you about the project.
so, TeaVM is the compiler of Java bytecode to JavaScript. The idea of creating TeaVM came to me while I was working full-stack Java developer and used to write a GWT frontend. In those days (somewhere about 5 years ago) were not widely used tools like node.js, webpack, babel, TypeScript; Angular was in the first version, and alternatives like React vue.js was not at all. So in all seriousness people were testing the websites in IE7 (and some who are not lucky with customers, even IE6). In General, the ecosystem of JavaScript was much less Mature than now, and without pain use JavaScript to write it.
GWT I liked the fact that amid all this he seemed an adequate solution, although not devoid of its disadvantages. The main problems are listed below:
the
-
the
- the speed of the rebuilding leaves much to be desired. Well, GWT is very slow. Started compiling and went to drink tea with cookies. the
- GWT receives the source code in Java and therefore, first, slow (to parse and resolvit Java code is not an easy task), and secondly, does not support anything other than Java, thirdly, he lags far behind even support new versions of Java. the
- To GWT just a terrible framework for creating UI. On the one hand, it tries to abstract away from the DOM, on the other hand, is not always in this to the end, abstractions leak, and correct it by intervening directly in DOM is not easy because you have to break through thick layers of abstraction. In addition, while the whole civilized world followed the path of declarative descriptions of the markup (in WPF .NET, JavaFX, Flex, this modern frameworks for JavaScript), GWT the old fashioned way are forced to collect UI from the widgets.
I did not think that the idea of writing web applications in Java — bad. All the shortcomings of the GWT was from what Google is, I think, just not invested sufficient resources in its development. I preferred to put up with the disadvantages of GWT, but would not go to JavaScript.
And then I thought — why not use as an input material Java bytecode? Byte code maintains a lot of information about the source program, so much that Decompiler software manage then almost exactly-in-exactly recover the sources. Javaс makes all the hard work of generating bytecode, so the generated JavaScript should spend quite a bit of time. Plus get support other languages for the JVM and nearly free support for new versions of Java (byte code is much more conservative than the Java language).
What interesting things happened with the project
I have said that the project has been a lot of interesting things. Here are the most important points that I would like to tell:
the
-
the
- added support for threads (threads). In JavaScript there is not, WebWorkers is not about that, because, unlike threads, they don't have shared state, i.e. you cannot create an object in one worker and give it to another, without copying. Instead TeaVM able to convert the code methods so that their execution can be interrupted at certain fixed points (roughly analogous to the babel when it sees the await keyword). It has helped make some version of cooperative mnogozadachnosti when one thread reaching some long IO operations (or just any
Thread.sleep()
) is suspended and allows you to execute another trade.
the - added support for WebAssembly, still experimental. Supported arbitrary bytecode, but is not supported part of the JDK methods that are strongly tied to the JVM (this is especially different reflection). As no interop with anything; to invoke JavaScript, you have a very long dance with a tambourine. In General, for the support of WebAssembly I had to write your own GC and stack unwinding, so this WebAssembly low level! Over time, the promise to add support for GC and exceptions, but so far it is a real assembler.
Web framework
the Web framework for TeaVM called Flavour and it's written entirely in Java. Recently, I published the first version (0.1.0 room) on Maven Central. Ideologically it resembles Angular modern 2/4 and Vue.js but built entirely in idioms close a Java developer. For example, all the components of Flavour are usual Java classes, marked with annotation, there are no individual props and state, or any special object, which should encapsulate the properties that are changing. The language of the HTML templates are fully statically typed, any reference to a property of the object or invoking the event handler is checked at compile time, for example, a typo in the title of properties will simply not compile the project.
To communicate with the server Flavour offers to use interfaces marked with annotations, JAX-RS and data are transmitted using a DTO, which in turn are marked by annotations of Jackson. This should be useful to developers in Java that will very likely already know and use these APIs in their projects.
the question Arises: why create a framework, if there are available: React, Angular, Vue.js? You can just use JavaScript anteroom and nothing to invent. Of course, I thought about it. But no, it turns out to be much worse than it seems at first glance. These frameworks are built around idioms of dynamically typed JavaScript in it and object with the desired set of properties can be created out of thin air, and hope that the "class" object has magic method with the right name. In General, in the JavaScript world, the creators of the frameworks are not accustomed to thinking about typing. It can be overcome by writing all kinds of adapters, wrappers, preprocessors, generators. But in the end will turn the system more complicated source frameworks, so it was decided to write your own.
some examples
creating a project
of Course, everyone is welcome to read the documentation on the website. But to make it easier and faster to taste the Flavour, show you a small example here.
so, create a project using Maven:
the
mvn archetype:generate \
-DarchetypeGroupId=org.teavm.flavour \
-DarchetypeArtifactId=teavm-flavour-application \
-DarchetypeVersion=0.1.0
the generated project is Going as expected, with the command mvn package
.
Template engine
a Page is described by two files — a class code that describes its behavior (provides the data for display includes event handlers) and an HTML template. In the created project already has an example page, but I will give another example. You can replace the archetype generated from the sample, or just add two more file to the existing. Here is the class code of the page:
the
@BindTemplate("templates/fibonacci.html")
public class Fibonacci {
private List<Integer> values = new ArrayList<>();
public Fibonacci() {
values.add(0);
values.add(1);
}
public List<Integer> getValues() {
return values;
}
public void next() {
values.add(values.get(values.size() - 2) + values.get(values.size() - 1));
}
}
And here is its template:
the
<ul>
<!-- values is a shorthand for this.getValues() -->
<std:foreach var="fib" in="values">
<li>
<html:text value="fib"/>
</li>
</std:foreach>
<li>
<!-- actually, the event:click can simply execute some piece of code
but for convenience, it is recommended that event handler to fit in a method
and from the template just to call it -->
<button type="button" event:click="next()">Show next</button>
</li>
</ul>
std:foreach
, html:text
and event:click
are components of Flavour. The user can describe its components (interested in exactly how, you can read about it in documentation), they can either manually render your DOM, or do it through the template. In these components there is nothing special, they are not implemented by compiler magic. If you wish, you can write to their counterparts. For illustration, you can see the code html:text.
the
public static void main(String[] args) {
Templates.bind(new Fibonacci(), "application-content");
}
All the magic starts here. The framework creates an instance of the page class, and not controlling it. Instead, you create it by themselves and govern it as you wish, but the Flavour just generates the DOM, inserts it in the right place, changes the state of the object and redraws the DOM to reflect that change. By the way, the Flavour does not redraw the whole DOM, and change only the necessary part of it.
I Want to reiterate that sablani statically typed. If you make a mistake and write event:click="nxt()"
, the compiler will write the error message. This approach allows to generate faster code — Flavour does not spend time after page load to parse the Directive and to initialize binding; he does it all at compile time.
REST client
I would Now like to show how Flavour can be a useful web full stack developer. Assuming you are using some CXF in conjunction with JAX-RS. You have written about this interface:
the
@Path("math")
public interface MathService {
@GET
@Path("integers/sum")
int sum(@QueryParam("a") int a, @QueryParam("b") int b);
}
and implemented (e.g., in class MathServiceImpl
) to register the implementation in CXF. You have a small REST service. Now, to make him a request, from the client side you can write code like this:
the
MathService math = RESTClient.factory(MathService.class).createResource("api");
System.out.println(math.sum(2, 3));
(you can see in devtools that this code will send a GET request to /api/math/integers/sum?a=2&b=3
).
In General, it is not necessary in some way to explain the web client how to do a REST request to the desired endpoint. You already have a single image to the server and the client. You can continue to build and refactor REST-service, thus it is not necessary to synchronize it with the server-side and client-side — there is a synchronization point in interface MathService
.
In GWT there is a similar mechanism for GWT-RPC, but it forces you to generate additional async interface and use colbecki, while TeaVM is able to transform synchronous code into asynchronous. GWT-RPC uses its own, incompatible Protocol, so creating endpoint for GWT-RPC, you will not be able to reuse, for example, an iOS client.
What else is interesting?
of Course, in a small review article I can't tell at all. So just mentioning that this is interesting in TeaVM and Flavour, making them quite suitable for creating high-quality web applications.
the
-
the
- Integration with IntelliJ IDEA. To run it every time Maven is not serious, after all, Maven is used to build for production, not during development. TeaVM can be run directly from IDEA, simply press the Build button. the
- the Debugger. Without it you can not even talk about something as serious tool. TeaVM able to generate standard source maps; so you have your debug information format which is used in IDEA-plugin. the
- Very fast compiler. I spent effort on optimization, and byte code is such a primitive thing it is processed simply because there is nothing to brake. This is not Java, where you have, for example, types of output, generics, variance and captured types. In addition, when you run the compiler from the IDEA applies several techniques to reduce compilation time, such as running the compiler from the demon, and caching the information for subsequent assemblies. All this allows to achieve a quite comfortable speed rebuild JavaScript. the
- a Good optimizer will be able to cut from the impressive size of the JDK is very small piece, necessary for the normal operation of the application, and even make it quick. the
- Routing. Flavour knows how to parse and generate links, which from the point of view of the API — it's quite a statically typed interface. the
- form Validation. the
- Modal Windows with blocking APIs like Swing. the
- It is mentioned above — supports Kotlin and Scala, not just Java. Incidentally, a variant of the TodoMVC for TeaVM written in Kotlin.
Why Java on the web?
In recent years, ecosystem development JavaScript has become quite Mature. The developer easier not to use any heavy weight monsters like GWT, and to learn how to configure tools that have become de facto standards, and write in a modern language with lots of advanced features or even a modern statically typed language (TypeScript).
the Problem is that all this should be studied. To learn not just the syntax of the language (the experienced developer will spend a few days), to learn a lot of libraries, idioms, and developer tools. I am sure that yesterday experienced Java developer will take and deal with all of this in a couple of weeks, but the question is how well he can understand? Will he be able to write really good code? Even if you will understand and be able to there are still problems. First, the developer will have to switch context between Java and JavaScript. Secondly, the developer will have to spend more time setting up the instruments.
Well, I have a question to the Java community. Why is JavaScript such a persistent movement in the direction of the backend? I suspect that exactly one of those considerations, which I cited above. Why not be the same movement in the opposite direction? Here the community of JavaScript frontend developers have teamed up and created the backend ecosystem around node.js. What we, the community of Java developers, worse? There is a myth that supposedly nimble and lightweight JavaScript and Java is big and heavy, and not suitable for creating a frontend. Actually, my project I'm trying to prove that this is a myth, and that properly prepared Java can also be small and nimble. Example — implementation of TodoMVC, which occupies 125kb (try to write the TodoMVC React or Angular on 4 and look how big you'll get a bundle).
In conclusion
If you are interested in Flavour, here's some more material for studying:
the
-
the
- Documentation in English; the
- TodoMVC on the Kotlin; the
- Minesweeper in Java the
- CRUD Example, near-real, REST, validation, drop-down calendars, modal Windows and many others; the
- of Course, you can always ask me if something seemed unclear.
I would love to get feedback. Whether you are interested in my project, I would like you to try to write a small app? Do I still have to publish articles, and if so, about what you would like to read it? Can I publish your tutorials on Flavour, can you tell us how it works inside, how it works TeaVM. What you are interested in?