Vaadin Fusion index.html will result in offline-stub

301 views Asked by At

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

2

There are 2 answers

2
Marcus Hellberg On BEST ANSWER

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);
    }

}

1
Joakim Erdfelt On

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.