Skip to content

Commit

Permalink
refactor: rename views.ts to file-routes.ts (#2271)
Browse files Browse the repository at this point in the history
  • Loading branch information
taefi authored Apr 3, 2024
1 parent 0961d0b commit bf9054d
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -121,51 +125,59 @@ 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) {
clearRoutes();
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;
}
}

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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, AvailableViewInfo> availableViews) {
if (!deploymentConfiguration.isProductionMode()) {
loadLatestDevModeViewsJsonIfNeeded();
loadLatestDevModeFileRoutesJsonIfNeeded();
} else if (lastUpdated == null) {
// initial (and only) registration in production mode:
registerClientRoutes(LocalDateTime.now());
Expand All @@ -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)) {
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ClientRouteRegistryTest {
public void when_clearRoutes_isCalled_then_allRoutesAreCleared()
throws IOException {
mockDevelopmentMode();
createMockedDevModeViewsJson();
createMockedDevModeFileRouteJson();

clientRouteRegistry.registerClientRoutes(deploymentConfiguration);
Map<String, ClientViewConfig> allRoutes = clientRouteRegistry
Expand All @@ -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();
Expand All @@ -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<String, ClientViewConfig> allRoutes = clientRouteRegistry
Expand Down Expand Up @@ -106,7 +106,7 @@ public void when_developmentMode_then_loadClientViewsFromFrontendGenerated()
throws IOException {

mockDevelopmentMode();
createMockedDevModeViewsJson();
createMockedDevModeFileRouteJson();

clientRouteRegistry.registerClientRoutes(deploymentConfiguration);
Map<String, ClientViewConfig> allRoutes = clientRouteRegistry
Expand Down Expand Up @@ -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);
}
}
Expand Down
11 changes: 5 additions & 6 deletions packages/ts/file-router/src/vite-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`),
),
]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit bf9054d

Please sign in to comment.