Blog

An introduction to client-side TypeScript views in Vaadin 15

By  
Johannes Häyry
Johannes Häyry
·
On Feb 20, 2020 5:47:59 PM
·
In Product

typescript-v15-views
Vaadin is fast expanding its horizons. By the next LTS (estimated for 2021), the platform is looking to fully support two unique development models:

  • Java-only server-side development (the current primary Vaadin model).
  • TypeScript-based client-side UI development with seamless access to Java on the server-side. 

The release of Vaadin 15 in March is the first step in supporting the latter TypeScript / Java development model. Developers will now be able to add TypeScript views, which co-exist side-by-side with Java views, directly in their Vaadin applications. 

In this article, we discuss support for TypeScript in Vaadin 15, the benefits of the Vaadin approach to client-side UI development, followed by a quick code-example demonstrating the possibilities and simplicity of adding TypeScript views to a Vaadin app.

Want a peek at what’s in store for Vaadin? Check out Kavish’s blog post, “Vaadin 15 & beyond: An insider’s look at Vaadin’s future

This article was co-authored by Johannes Häyry and Kavish Weerawardane.

TypeScript support: Who is it for, and how do they win?

Vaadin 15 begins an ambitious journey towards enabling a seamless end-to-end full-stack development experience using TypeScript and Java, with out-of-the-box tooling that mitigates the need for any Webpack, TypeScript, or Node configuration. 

This approach is particularly geared towards hybrid full-stack teams consisting of both Java and front-end developers, as well as any Vaadin developers with a strong command of the client-side who are looking to build performant and installable progressive web apps (PWAs) with offline capabilities.

Want to learn more about progressive web applications? Our dedicated PWA handbook has the answers!

However, the core Vaadin Java-only server-side model you love is not going away. Instead, it will co-exist  independently alongside the new development model. Both will be fully-supported and maintained by dedicated product teams. Developers will have the freedom to select the model that best suits their team-structure and project requirements.

There are exciting new features on the horizon for the Java-only model as well. So, stay tuned to our blog and social media :) 

Now, getting back to the topic at hand, let’s have a quick look at some key benefits afforded by Vaadin’s newly-minted TypeScript support:

Proximity to the target platform

Vaadin 15 allows developers to stay close to the target platform (the browser) by writing the UI  code in TypeScript. At the same time, the Java backend remains only one async call away, with strongly-typed and secure APIs. This combination allows developers to:

  • Utilize any native web platform features, such as service workers and offline-support, directly.
  • Minimize the possibility of type errors through the implementation of automated type-checking of client-side code.
  • Seamlessly call Java code from the client-side, without writing boilerplate REST wrappers and redefining Java types in TypeScript manually.

Compatibility with existing Vaadin apps

Vaadin 15 provides the tooling necessary to write new views with TypeScript within an existing Vaadin app. This negates the need for any major codebase restructuring and allows TypeScript / JavaScript developers to contribute to the development of Vaadin apps with ease. 

Additionally, when adding TypeScript client-side code to an existing Vaadin app, developers can continue to use existing server-side routes and full Java or ‘PolymerTemplate’-based views.

Vaadin’s signature simplicity extended to the client-side

Vaadin’s emphasis on DX has always been one of its most attractive features. The cohesive combination of its server-side framework, theming engine, routing capabilities, component libraries, and build-tools, ensure that developers don’t spend much time evaluating, selecting, and setting-up these components, and they can instead focus on their app’s functionality and user-experience. 

Despite this being our initial entry into the field, Vaadin 15 offers all the front-end build tools and configuration options required to get you up and running right out of the box. This includes all relevant Webpack, TypeScript, and Node configuration, which you can later customize to suit your requirements. While its overall client-side feature-set may still be on the barebones side of the spectrum, it is a solid foundation to build on 

How do client-side views work in Vaadin 15?

The views created in Vaadin 15 using TypeScript on the client-side have a few unique features:

  • Routing happens on the client-side and also works offline.
  • These client-side routes can live in the same application and co-exist with server-side routes and components.
  • The server-side of the app knows nothing about these views. This enables the creation of views that have no server-side state. This, in turn, affords some significant benefits:
  • Greater horizontal scalability, as the UI state doesn’t need to be replicated across nodes (a challenging task on the best of days).
  • Increasingly performant and less resource-intensive apps resulting from a smaller memory footprint per user on the server-side.

Now that we have a grasp of the characteristics of client-side views in Vaadin 15, let’s take a brief look at how it all works.

Under the hood

Vaadin 15 handles bootstrapping on the client-side using a generated (but customizable) index.ts file. While this approach does require the use of a client-side Vaadin router (when client-side routes are present), you can easily fallback to the server-side, if a client-side route is not detected. 

On the server-side, routes work in the same way they always have.

To access the server-side from TypeScript, you need to create endpoint Java classes. When this is done, Vaadin:

  • Generates TypeScript code to call the endpoint methods and the types used in the endpoint methods.
  • Secures endpoints by default, allowing you to manually open up the endpoints to anonymous access or specifically-permitted user-roles.

The following section briefly examines the features and improvements due in subsequent Vaadin versions.

Forthcoming improvements to the TypeScript + Java development model

As noted above, Vaadin 15 is an early foray into this space. It does have a few limitations, but many planned improvements are on the horizon. For example, many helpers and utilities to reduce boilerplate code are being developed, including:

  • Advanced form binding for TypeScript views, with support for validation rules from your server-side code.
  • Lazy-loading data binding of the server-side data to the client-side components.
  • Server push for easy subscription to server-side data flows.

These and additional features will be implemented in subsequent versions of Vaadin leading up to our next LTS release in 2021.

Want a complete run-down of Vaadin 15’s capabilities? Have a read through our Vaadin 15 release page to learn more: https://vaadin.com/releases/vaadin-15

Code-example / Let’s get coding

In our code example, we create a view that queries entities from the endpoint and populates them into a vaadin-grid.

The complete code for this example is available on GitHub

Let’s assume that we have two entities named “Contact” and “Company”:

// Contact.java
@Entity
public class Contact {
  private Integer id;
  private String firstName = "";
  private String lastName = "";
  private Company company;
  private String email = "";
  // getters and setters
}

and

// Company.java
public class Company {
  private Integer id;
  private String name;
  // getters and setters
}

 

Assuming that we also have a Spring service named`ContactService , which returns contacts from a repository:

public List<Contact> findAll() {
  return contactRepository.findAll();
}

We are now able to create an endpoint which can later be called from a view created using LitElement and TypeScript.

// MasterDetailEndpoint.java
import com.vaadin.flow.server.connect.Endpoint;
import com.vaadin.flow.server.connect.auth.AnonymousAllowed;
import org.springframework.beans.factory.annotation.Autowired;

@Endpoint
@AnonymousAllowed
public class MasterDetailEndpoint {
  private final ContactService contactService;

  @Autowired
  public MasterDetailEndpoint(ContactService contactService) {
    this.contactService = contactService;
  }

  public List<Contact> getEmployees() {
    return contactService.findAll();
  }
}

When you launch the application with Maven, Vaadin generates the necessary client-side code into the directory `frontend/generated/*`, thereby allowing access to the endpoints and the types used. 

You can continue editing the frontend code while the application is running, and have changes and endpoints applied without a server restart.

Now, let’s start creating a TypeScript view.

In the interest of keeping things on-topic, this article skips over some boilerplate code related to client-side routing. We recommend having a look at the full-example on GitHub, or the Vaadin 15 documentation to learn how client-side routing is set-up. 

We begin by importing a few things.

// MasterDetailView.ts
import { customElement, html, LitElement, query, unsafeCSS } from 'lit-element';
import '@vaadin/vaadin-grid/vaadin-grid';
import '@vaadin/vaadin-grid/vaadin-grid-column';
// import the remote endpoint
import * as viewEndpoint from '../../generated/MasterDetailEndpoint';
// import types used in the endpoint
import Contact from '../../generated/org/vaadin/example/backend/entity/Contact';

Now, we create a view that queries the Contacts from the endpoint and populates them into a vaadin-grid. 

Note that this example uses LitElement, which is a lightweight successor to Polymer. As a side-note, Vaadin is in the process of gradually introducing LitElement as an eventual replacement for Polymer throughout the platform. At the moment, both can be used side-by-side.

Want to learn more about LitElement? Marcus created a comprehensive LitElement tutorial which covers many of the fundamentals.

// MasterDetailView.ts
@customElement('master-detail-view')
export class MasterDetailViewElement extends LitElement {
  static get styles() {
    return [CSSModule('lumo-typography'), unsafeCSS(styles)];
  }
  
  @query('#grid')
  private grid: any;
  
  render() {
    return html`<div>
	  <vaadin-grid id="grid" theme="no-border">
	    <vaadin-grid-column header="First name" path="firstName"></vaadin-grid-column>
		<vaadin-grid-column header="Last name" path="lastName"></vaadin-grid-column>
	    <vaadin-grid-column header="Email" path="email"></vaadin-grid-column>
	  </vaadin-grid>
	</div>`;
  }
  
  // Wait until all elements in the template are ready to set their properties
  async firstUpdated(changedProperties: any) {
    super.firstUpdated(changedProperties);
	// Retrieve data from the server-side endpoint.
	const persons = await viewEndpoint.getEmployees();
	this.grid.items = persons;
  }
}

These code samples aim to demonstrate the new capabilities.As such, some boilerplate code has been omitted to keep things clear and concise. We recommend reading through the full example at GitHub.

Try it yourself

Creating with Vaadin 15 is simple. To get started:

  1. Create a new project in start.vaadin.com and choose TypeScript as the implementation for one or more of the views. 
  2. Or upgrade an existing Vaadin 14 application by following the upgrade instructions.

Don’t forget to let us know what you think.

Please note that the final, stable release of Vaadin 15 is due out on March 4th. Any apps built prior to that will be on a beta version.

We are very excited by the world of possibilities Vaadin 15’s TypeScript support opens up for the community. How about you? Let us know your thoughts in the comments!

Happy coding :) 

Johannes Häyry
Johannes Häyry
I'm a developer disguised as a product marketer. I usually write about new Vaadin releases or the upcoming cool features on the roadmap.
Other posts by Johannes Häyry