From bf9054dc91bfef95e43378047e875149e3bfbceb Mon Sep 17 00:00:00 2001 From: Soroosh Taefi Date: Wed, 3 Apr 2024 11:20:33 +0300 Subject: [PATCH] refactor: rename views.ts to file-routes.ts (#2271) --- .../hilla/route/ClientRouteRegistry.java | 44 ++++++++++++------- ...RouteUnifyingIndexHtmlRequestListener.java | 33 +++++++++----- .../RouteUnifyingServiceInitListener.java | 2 + .../hilla/route/ClientRouteRegistryTest.java | 27 ++++++------ .../VAADIN/{views.json => file-routes.json} | 0 packages/ts/file-router/src/vite-plugin.ts | 11 +++-- .../src/vite-plugin/createRoutesFromMeta.ts | 6 ++- .../src/vite-plugin/generateRuntimeFiles.ts | 8 +++- .../vite-plugin/createRoutesFromMeta.spec.ts | 4 +- .../vite-plugin/generateRuntimeFiles.spec.ts | 4 +- 10 files changed, 84 insertions(+), 55 deletions(-) rename packages/java/endpoint/src/test/resources/META-INF/VAADIN/{views.json => file-routes.json} (100%) diff --git a/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/ClientRouteRegistry.java b/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/ClientRouteRegistry.java index a571c3bbd2..67f5c31c54 100644 --- a/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/ClientRouteRegistry.java +++ b/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/ClientRouteRegistry.java @@ -42,6 +42,10 @@ @Component public class ClientRouteRegistry implements Serializable { + public static final String FILE_ROUTES_JSON_NAME = "file-routes.json"; + public static final String FILE_ROUTES_JSON_PROD_PATH = "/META-INF/VAADIN/" + + FILE_ROUTES_JSON_NAME; + /** * A map of registered routes and their corresponding client view * configurations with ordered insertion. @@ -121,25 +125,29 @@ private String removeTrailingSlash(String path) { } /** - * Registers client routes from views.json file generated by the - * file-router's Vite plugin. The views.json file is expected to be in the - * frontend/generated folder in dev mode and in the META-INF/VAADIN folder - * in production mode. + * Registers client routes from file-routes.json file generated by the + * file-router's Vite plugin. The file-routes.json file is expected to be in + * the frontend/generated folder in dev mode and in the META-INF/VAADIN + * folder in production mode. * * @param deploymentConfiguration * the deployment configuration + * + * @return {@code true} if the client routes were successfully registered, + * {@code false} otherwise */ - public void registerClientRoutes( + public boolean registerClientRoutes( DeploymentConfiguration deploymentConfiguration) { var viewsJsonAsResource = getViewsJsonAsResource( deploymentConfiguration); - if (viewsJsonAsResource == null || !Paths - .get(viewsJsonAsResource.getPath()).toFile().exists()) { + if (viewsJsonAsResource == null) { LOGGER.debug( - "No 'views.json' found either in the frontend/generated " - + "folder or in the META-INF/VAADIN folder. Skipping client " - + "route registration."); - return; + "No {} found under {} directory. Skipping client route registration.", + FILE_ROUTES_JSON_NAME, + deploymentConfiguration.isProductionMode() + ? "'META-INF/VAADIN'" + : "'frontend/generated'"); + return false; } try (var source = viewsJsonAsResource.openStream()) { if (source != null) { @@ -147,10 +155,13 @@ public void registerClientRoutes( registerAndRecurseChildren("", mapper.readValue(source, new TypeReference<>() { })); + return true; } + return false; } catch (IOException e) { - LOGGER.warn("Failed load client views from {}", + LOGGER.warn("Failed load {} from {}", FILE_ROUTES_JSON_NAME, viewsJsonAsResource.getPath(), e); + return false; } } @@ -158,14 +169,15 @@ private URL getViewsJsonAsResource( DeploymentConfiguration deploymentConfiguration) { var isProductionMode = deploymentConfiguration.isProductionMode(); if (isProductionMode) { - return getClass().getResource("/META-INF/VAADIN/views.json"); + return getClass().getResource(FILE_ROUTES_JSON_PROD_PATH); } try { return deploymentConfiguration.getFrontendFolder().toPath() - .resolve("generated").resolve("views.json").toUri().toURL(); + .resolve("generated").resolve(FILE_ROUTES_JSON_NAME).toUri() + .toURL(); } catch (MalformedURLException e) { - LOGGER.warn("Failed to find views.json under frontend/generated", - e); + LOGGER.warn("Failed to find {} under frontend/generated", + FILE_ROUTES_JSON_NAME, e); throw new RuntimeException(e); } } diff --git a/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/RouteUnifyingIndexHtmlRequestListener.java b/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/RouteUnifyingIndexHtmlRequestListener.java index 01c6a2406c..c5f4bd7d6d 100644 --- a/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/RouteUnifyingIndexHtmlRequestListener.java +++ b/packages/java/endpoint/src/main/java/com/vaadin/hilla/route/RouteUnifyingIndexHtmlRequestListener.java @@ -78,22 +78,27 @@ public void modifyIndexHtmlResponse(IndexHtmlResponse response) { collectServerViews(availableViews); if (availableViews.isEmpty()) { + LOGGER.debug( + "No server-side nor client-side views found, skipping response modification."); return; } try { - final String viewsJson = mapper.writeValueAsString(availableViews); - final String script = SCRIPT_STRING.formatted(viewsJson); + final String fileRoutesJson = mapper + .writeValueAsString(availableViews); + final String script = SCRIPT_STRING.formatted(fileRoutesJson); response.getDocument().head().appendElement("script") .appendChild(new DataNode(script)); } catch (IOException e) { - LOGGER.error("Failed to write server views to index response", e); + LOGGER.error( + "Failure while to write client and server routes to index html response", + e); } } protected void collectClientViews( Map availableViews) { if (!deploymentConfiguration.isProductionMode()) { - loadLatestDevModeViewsJsonIfNeeded(); + loadLatestDevModeFileRoutesJsonIfNeeded(); } else if (lastUpdated == null) { // initial (and only) registration in production mode: registerClientRoutes(LocalDateTime.now()); @@ -109,16 +114,17 @@ protected void collectClientViews( } - private void loadLatestDevModeViewsJsonIfNeeded() { - var devModeViewsJsonFile = deploymentConfiguration.getFrontendFolder() - .toPath().resolve("generated").resolve("views.json").toFile(); - if (!devModeViewsJsonFile.exists()) { - LOGGER.warn("Failed to find views.json under {}", + private void loadLatestDevModeFileRoutesJsonIfNeeded() { + var devModeFileRoutesJsonFile = deploymentConfiguration + .getFrontendFolder().toPath().resolve("generated") + .resolve("file-routes.json").toFile(); + if (!devModeFileRoutesJsonFile.exists()) { + LOGGER.debug("No file-routes.json found under {}", deploymentConfiguration.getFrontendFolder().toPath() .resolve("generated")); return; } - var lastModified = devModeViewsJsonFile.lastModified(); + var lastModified = devModeFileRoutesJsonFile.lastModified(); var lastModifiedTime = Instant.ofEpochMilli(lastModified) .atZone(ZoneId.systemDefault()).toLocalDateTime(); if (lastUpdated == null || lastModifiedTime.isAfter(lastUpdated)) { @@ -127,8 +133,11 @@ private void loadLatestDevModeViewsJsonIfNeeded() { } private void registerClientRoutes(LocalDateTime newLastUpdated) { - lastUpdated = newLastUpdated; - clientRouteRegistry.registerClientRoutes(deploymentConfiguration); + var hasClientRoutesRegistered = clientRouteRegistry + .registerClientRoutes(deploymentConfiguration); + if (hasClientRoutesRegistered) { + lastUpdated = newLastUpdated; + } } protected void collectServerViews( diff --git a/packages/java/endpoint/src/main/java/com/vaadin/hilla/startup/RouteUnifyingServiceInitListener.java b/packages/java/endpoint/src/main/java/com/vaadin/hilla/startup/RouteUnifyingServiceInitListener.java index 06dbd8897d..589795c8a6 100644 --- a/packages/java/endpoint/src/main/java/com/vaadin/hilla/startup/RouteUnifyingServiceInitListener.java +++ b/packages/java/endpoint/src/main/java/com/vaadin/hilla/startup/RouteUnifyingServiceInitListener.java @@ -54,6 +54,8 @@ public RouteUnifyingServiceInitListener( public void serviceInit(ServiceInitEvent event) { var deploymentConfiguration = event.getSource() .getDeploymentConfiguration(); + LOGGER.debug("deploymentConfiguration.isReactEnabled() = {}", + deploymentConfiguration.isReactEnabled()); if (deploymentConfiguration.isReactEnabled()) { var routeUnifyingIndexHtmlRequestListener = new RouteUnifyingIndexHtmlRequestListener( clientRouteRegistry, deploymentConfiguration); diff --git a/packages/java/endpoint/src/test/java/com/vaadin/hilla/route/ClientRouteRegistryTest.java b/packages/java/endpoint/src/test/java/com/vaadin/hilla/route/ClientRouteRegistryTest.java index 16a6dbccfa..574e360999 100644 --- a/packages/java/endpoint/src/test/java/com/vaadin/hilla/route/ClientRouteRegistryTest.java +++ b/packages/java/endpoint/src/test/java/com/vaadin/hilla/route/ClientRouteRegistryTest.java @@ -30,7 +30,7 @@ public class ClientRouteRegistryTest { public void when_clearRoutes_isCalled_then_allRoutesAreCleared() throws IOException { mockDevelopmentMode(); - createMockedDevModeViewsJson(); + createMockedDevModeFileRouteJson(); clientRouteRegistry.registerClientRoutes(deploymentConfiguration); Map allRoutes = clientRouteRegistry @@ -43,7 +43,7 @@ public void when_clearRoutes_isCalled_then_allRoutesAreCleared() } @Test - public void when_developmentMode_and_noViewsJsonFile_then_noRoutesAreRegistered() + public void when_developmentMode_and_noFileRouteJsonFile_then_noRoutesAreRegistered() throws IOException { mockDevelopmentMode(); @@ -55,12 +55,12 @@ public void when_developmentMode_and_noViewsJsonFile_then_noRoutesAreRegistered( } @Test - public void when_developmentMode_and_emptyViewsJsonFile_then_noRoutesAreRegistered() + public void when_developmentMode_and_emptyFileRouteJsonFile_then_noRoutesAreRegistered() throws IOException { mockDevelopmentMode(); - projectRoot.newFile("frontend/generated/views.json"); + projectRoot.newFile("frontend/generated/file-routes.json"); clientRouteRegistry.registerClientRoutes(deploymentConfiguration); Map allRoutes = clientRouteRegistry @@ -106,7 +106,7 @@ public void when_developmentMode_then_loadClientViewsFromFrontendGenerated() throws IOException { mockDevelopmentMode(); - createMockedDevModeViewsJson(); + createMockedDevModeFileRouteJson(); clientRouteRegistry.registerClientRoutes(deploymentConfiguration); Map allRoutes = clientRouteRegistry @@ -145,17 +145,18 @@ private void mockDevelopmentMode() throws IOException { .thenReturn(frontendGeneratedDir.getParentFile()); } - private void createMockedDevModeViewsJson() throws IOException { - var viewsJsonProdAsResource = getClass() - .getResource("/META-INF/VAADIN/views.json"); - assert viewsJsonProdAsResource != null; + private void createMockedDevModeFileRouteJson() throws IOException { + var fileRoutesJsonProdAsResource = getClass() + .getResource(ClientRouteRegistry.FILE_ROUTES_JSON_PROD_PATH); + assert fileRoutesJsonProdAsResource != null; String hierarchicalRoutesAsString = IOUtils.toString( - viewsJsonProdAsResource.openStream(), StandardCharsets.UTF_8); + fileRoutesJsonProdAsResource.openStream(), + StandardCharsets.UTF_8); String addedDevToRootRoute = hierarchicalRoutesAsString .replaceFirst("\"route\": \"\",", "\"route\": \"dev\","); - var viewsJsonFile = projectRoot - .newFile("frontend/generated/views.json"); - try (PrintWriter writer = new PrintWriter(viewsJsonFile)) { + var fileRoutesJsonFile = projectRoot.newFile("frontend/generated/" + + ClientRouteRegistry.FILE_ROUTES_JSON_NAME); + try (PrintWriter writer = new PrintWriter(fileRoutesJsonFile)) { writer.println(addedDevToRootRoute); } } diff --git a/packages/java/endpoint/src/test/resources/META-INF/VAADIN/views.json b/packages/java/endpoint/src/test/resources/META-INF/VAADIN/file-routes.json similarity index 100% rename from packages/java/endpoint/src/test/resources/META-INF/VAADIN/views.json rename to packages/java/endpoint/src/test/resources/META-INF/VAADIN/file-routes.json diff --git a/packages/ts/file-router/src/vite-plugin.ts b/packages/ts/file-router/src/vite-plugin.ts index 011e91d643..2d4b0cd3e6 100644 --- a/packages/ts/file-router/src/vite-plugin.ts +++ b/packages/ts/file-router/src/vite-plugin.ts @@ -70,8 +70,8 @@ export default function vitePluginFileSystemRouter({ _logger.info(`The output directory: ${String(_outDir)}`); runtimeUrls = { - json: new URL('views.json', isDevMode ? _generatedDir : _outDir), - code: new URL('views.ts', _generatedDir), + json: new URL('file-routes.json', isDevMode ? _generatedDir : _outDir), + code: new URL('file-routes.ts', _generatedDir), }; }, async buildStart() { @@ -89,10 +89,9 @@ export default function vitePluginFileSystemRouter({ return; } - generateRuntimeFiles(_viewsDir, runtimeUrls, extensions, _logger).catch((e: unknown) => - _logger.error(String(e)), - ); - server.hot.send({ type: 'full-reload' }); + generateRuntimeFiles(_viewsDir, runtimeUrls, extensions, _logger) + .then(() => server.hot.send({ type: 'full-reload' })) + .catch((e: unknown) => _logger.error(String(e))); }; server.watcher.on('add', changeListener); diff --git a/packages/ts/file-router/src/vite-plugin/createRoutesFromMeta.ts b/packages/ts/file-router/src/vite-plugin/createRoutesFromMeta.ts index 095ac771b9..f1a221ab48 100644 --- a/packages/ts/file-router/src/vite-plugin/createRoutesFromMeta.ts +++ b/packages/ts/file-router/src/vite-plugin/createRoutesFromMeta.ts @@ -123,7 +123,9 @@ export default routes; ], ); - const file = createSourceFile(routeDeclaration, 'views.ts'); - + const file = createSourceFile(routeDeclaration, 'file-routes.ts'); + // also keep the old file temporarily for compatibility purposes: + const tempFile = createSourceFile(routeDeclaration, 'views.ts'); + printer.printFile(tempFile); return printer.printFile(file); } diff --git a/packages/ts/file-router/src/vite-plugin/generateRuntimeFiles.ts b/packages/ts/file-router/src/vite-plugin/generateRuntimeFiles.ts index 7babaf63c6..17f3a9da31 100644 --- a/packages/ts/file-router/src/vite-plugin/generateRuntimeFiles.ts +++ b/packages/ts/file-router/src/vite-plugin/generateRuntimeFiles.ts @@ -60,13 +60,17 @@ export async function generateRuntimeFiles( logger.info('Collected file-based routes'); const runtimeRoutesCode = createRoutesFromMeta(routeMeta, urls); const viewConfigJson = await createViewConfigJson(routeMeta); - + const tempUrl = new URL('views.ts', urls.code.href); await Promise.all([ generateRuntimeFile(urls.json, viewConfigJson).then(() => logger.info(`Frontend route list is generated: ${String(urls.json)}`), ), generateRuntimeFile(urls.code, runtimeRoutesCode).then(() => - logger.info(`Views module is generated: ${String(urls.code)}`), + logger.info(`File Route module is generated: ${String(urls.code)}`), + ), + // also keep the old file temporarily for compatibility purposes: + generateRuntimeFile(tempUrl, runtimeRoutesCode).then(() => + logger.info(`Views module is generated: ${String(tempUrl)}`), ), ]); } diff --git a/packages/ts/file-router/test/vite-plugin/createRoutesFromMeta.spec.ts b/packages/ts/file-router/test/vite-plugin/createRoutesFromMeta.spec.ts index aa09b02c3d..415d009421 100644 --- a/packages/ts/file-router/test/vite-plugin/createRoutesFromMeta.spec.ts +++ b/packages/ts/file-router/test/vite-plugin/createRoutesFromMeta.spec.ts @@ -17,8 +17,8 @@ describe('@vaadin/hilla-file-router', () => { dir = pathToFileURL(join(tmpdir(), 'file-router/')); meta = createTestingRouteMeta(new URL('./views/', dir)); runtimeUrls = { - json: new URL('server/views.json', dir), - code: new URL('generated/views.ts', dir), + json: new URL('server/file-routes.json', dir), + code: new URL('generated/file-routes.ts', dir), }; }); diff --git a/packages/ts/file-router/test/vite-plugin/generateRuntimeFiles.spec.ts b/packages/ts/file-router/test/vite-plugin/generateRuntimeFiles.spec.ts index 9c08d1314f..bea049e331 100644 --- a/packages/ts/file-router/test/vite-plugin/generateRuntimeFiles.spec.ts +++ b/packages/ts/file-router/test/vite-plugin/generateRuntimeFiles.spec.ts @@ -21,8 +21,8 @@ describe('@vaadin/hilla-file-router', () => { viewsDir = new URL('views/', tmp); runtimeUrls = { - json: new URL('server/views.json', tmp), - code: new URL('generated/views.ts', tmp), + json: new URL('server/file-routes.json', tmp), + code: new URL('generated/file-routes.ts', tmp), }; await createTestingRouteFiles(viewsDir);