1

I'm very new to Jetty and Vaadin. I try to get a Jetty running hosting a minimal Vaadin Fusion example.
However, already on the first visit on my empty index.html I got a connection lost banner and a 404 because it tries to redirect to an /offline-stub.html that I don't have.

The Produced view:

enter image description here

In the network tap, you can see that Vaadin somehow initiates the redirect:

enter image description here

My index.html is very simple:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Vaadin Grocery App</title>
    <style>
      body {
        margin: 0;
        width: 100vw;
        height: 100vh;
      }

      #outlet {
        height: 100%;
      }
    </style>
    <!-- index.ts is included here automatically (either by the dev server or during the build) -->
  </head>

  <body>
   <h1>hello</h1>
  </body>
</html>

an index.ts as well:

import { Router } from '@vaadin/router';
import { routes } from './routes';
import { appStore } from './stores/app-store';

export const router = new Router(document.querySelector('#outlet'));

router.setRoutes(routes);

window.addEventListener('vaadin-router-location-changed', (e) => {
  appStore.setLocation((e as CustomEvent).detail.location);
  const title = appStore.currentViewTitle;
  if (title) {
    document.title = title + ' | ' + appStore.applicationName;
  } else {
    document.title = appStore.applicationName;
  }
});

I initiate the Jetty like this:

 public static void main(String[] args) throws URISyntaxException, IOException {

        Log.setLog(new StdErrLog());
        System.out.println("Server starting...");
       

        String extForm = webRoot + "/webapp";
        System.out.println(extForm);

        final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");

        final ResourceHandler resHandler = new ResourceHandler();
        resHandler.setResourceBase(extForm);
        final ContextHandler ctx = new ContextHandler("/");
        ctx.setHandler(resHandler);

        Server embeddedServer = new Server(8080);

        embeddedServer.insertHandler(context); // Rest/Servlets
        embeddedServer.insertHandler(resHandler); // HTML Resources
        try {
            embeddedServer.start();
            embeddedServer.join();
        } catch (Exception e) {
            System.err.println("Server error:\n" + e);
        }
        System.out.println("Server stopped");
    }

Webroot, extform -values are correct and the files are at those specified locations on disk:

enter image description here

ollitietavainen
  • 3,900
  • 13
  • 30

2 Answers2

2

Please note that Vaadin Fusion only supports Spring Boot backends right now. Because of that, you don't need to configure your own server. Starting the Spring Boot app is enough. I recommend creating a project starter on https://start.vaadin.com and basing your project on that.

@SpringBootApplication
public class Application extends SpringBootServletInitializer implements AppShellConfigurator {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Marcus Hellberg
  • 1,853
  • 10
  • 16
  • Thanks you for the information. Could you explain a little why Spring Boot is requiered. Spring Boot can be configured to use jetty as an underlying servlet container. What else does spring boot bring to the table, that's requiered by vaadin fusion – theMahaloRecords Dec 06 '21 at 12:05
  • 1
    Fusion uses Spring Boot for registering and managing endpoints. We wanted to start out with a single opinionated tech stack so we can validate and build the product faster. Once we're at a good point, we will certainly look into supporting alternate technologies like Quarkus etc. – Marcus Hellberg Dec 07 '21 at 15:52
1

Don't mix ResourceHandler and ServletContextHandler together like that.

Remove the ResourceHandler entirely (and it's associated ContextHandler)

Properly define the ServletContextHandler with a resource base.
Then ensure that ServletContextHandler has a DefaultServlet setup.

That's it, that's all you have to do.

Oh, and don't declare your REST endpoints on url-pattern / or /* as that also prevents static resource serving. Those url-patterns basically mean that your servlet endpoint (your REST lib?) is the only thing, and it's responsible for 100% of requests.

The reason you don't mix things like this is because both ServletContextHandler and ResourceHandler are terminal (once entered, they must respond with an HTTP response).

If you use the ServletContext properly, then the best match (see Servlet url-pattern matching rules, eg: longest match) against the url-pattern is used, serving static content or your REST endpoint depending on what your client is requesting.

Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136