class IndexHtmlRequestHandler extends JavaScriptBootstrapHandler {

    @Override
    public boolean synchronizedHandleRequest(VaadinSession session,
            VaadinRequest request, VaadinResponse response) throws IOException {
        DeploymentConfiguration config = session.getConfiguration();

        Document indexDocument = config.isProductionMode()
                ? getCachedIndexHtmlDocument(request.getService())
                : getIndexHtmlDocument(request.getService());

        prependBaseHref(request, indexDocument);

        JsonObject initialJson = Json.createObject();

        if (request.getService().getBootstrapInitialPredicate()
                .includeInitialUidl(request)) {
            includeInitialUidl(initialJson, session, request, response);

            indexHtmlResponse = new IndexHtmlResponse(request, response, indexDocument, UI.getCurrent());

            // App might be using classic server-routing, which is true
            // unless we detect a call to JavaScriptBootstrapUI.connectClient
            session.setAttribute(SERVER_ROUTING, Boolean.TRUE);
        } else {
            indexHtmlResponse = new IndexHtmlResponse(request, response, indexDocument);
        }

        addInitialFlow(initialJson, indexDocument, session);

        configureErrorDialogStyles(indexDocument);

        showWebpackErrors(indexDocument);

        response.setContentType(CONTENT_TYPE_TEXT_HTML_UTF_8);

        VaadinContext context = session.getService().getContext();
        AppShellRegistry registry = AppShellRegistry.getInstance(context);

        if (!config.isProductionMode()) {
            UsageStatisticsExporter.exportUsageStatisticsToDocument(indexDocument);
        }

        // modify the page based on the @PWA annotation
        setupPwa(indexDocument, session.getService());

        // modify the page based on the @Meta, @ViewPort, @BodySize and @Inline annotations
        // and on the AppShellConfigurator
        registry.modifyIndexHtml(indexDocument, request);

        // modify the page based on registered IndexHtmlRequestListener:s
        request.getService().modifyIndexHtmlResponse(indexHtmlResponse);

        if (config.isDevModeLiveReloadEnabled()) {
            addDevmodeGizmo(indexDocument, session, request);
        }
        try {
            response.getOutputStream()
                    .write(indexDocument.html().getBytes(UTF_8));
        } catch (IOException e) {
            getLogger().error("Error writing 'index.html' to response", e);
            return false;
        }
        return true;
    }

}