Skip to content

Commit

Permalink
fix: Require production bundle for annotation (#16768)
Browse files Browse the repository at this point in the history
If the LoadDependenciesOnStartup
annotation is added a production
bunlde should always be built.
  • Loading branch information
caalador committed May 11, 2023
1 parent 436faa6 commit 683df7f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 21 deletions.
Expand Up @@ -28,6 +28,7 @@
import com.vaadin.flow.internal.UsageStatistics;
import com.vaadin.flow.internal.hilla.EndpointRequestUtil;
import com.vaadin.flow.server.Constants;
import com.vaadin.flow.server.LoadDependenciesOnStartup;
import com.vaadin.flow.server.Mode;
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
import com.vaadin.flow.server.frontend.scanner.FrontendDependenciesScanner;
Expand Down Expand Up @@ -142,6 +143,13 @@ private static boolean needsBuildProdBundle(Options options,
ClassFinder finder) throws IOException {
String statsJsonContent = findProdBundleStatsJson(finder);

if (!finder.getAnnotatedClasses(LoadDependenciesOnStartup.class)
.isEmpty()) {
getLogger()
.info("Custom eager routes defined. Require bundle build.");
return true;
}

if (statsJsonContent == null) {
// without stats.json in bundle we can not say if it is up-to-date
getLogger().info(
Expand Down
Expand Up @@ -23,8 +23,10 @@
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.di.Lookup;
import com.vaadin.flow.server.Constants;
import com.vaadin.flow.server.LoadDependenciesOnStartup;
import com.vaadin.flow.server.Mode;
import com.vaadin.flow.server.frontend.scanner.ChunkInfo;
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
Expand Down Expand Up @@ -151,16 +153,15 @@ private JsonObject getBasicStats() {
}

@Test
public void noDevBundle_bundleCompilationRequires() throws IOException {
public void noDevBundle_bundleCompilationRequires() {
final boolean needsBuild = BundleValidationUtil.needsBuild(options,
Mockito.mock(FrontendDependenciesScanner.class), finder, mode);
Assert.assertTrue("Bundle should require creation if not available",
needsBuild);
}

@Test
public void devBundleStatsJsonMissing_bundleCompilationRequires()
throws IOException {
public void devBundleStatsJsonMissing_bundleCompilationRequires() {
devBundleUtils
.when(() -> DevBundleUtils.getDevBundleFolder(Mockito.any()))
.thenReturn(temporaryFolder.getRoot());
Expand Down Expand Up @@ -200,7 +201,42 @@ public void hashesMatch_noNpmPackages_noCompilationRequired()

final boolean needsBuild = BundleValidationUtil.needsBuild(options,
depScanner, finder, mode);
Assert.assertFalse("Missing stats.json should require bundling",
Assert.assertFalse("Matching hashes should not require compilation",
needsBuild);
}

@Test
public void loadDependenciesOnStartup_annotatedClassInProject_compilationRequiredForProduction()
throws IOException {
Assume.assumeTrue(mode == Mode.PRODUCTION);

File packageJson = new File(temporaryFolder.getRoot(), "package.json");
packageJson.createNewFile();

FileUtils.write(packageJson,
"{\"dependencies\": {" + "\"@vaadin/router\": \"1.7.5\"}, "
+ "\"vaadin\": { \"hash\": \"aHash\"} }",
StandardCharsets.UTF_8);

final FrontendDependenciesScanner depScanner = Mockito
.mock(FrontendDependenciesScanner.class);
Mockito.when(depScanner.getPackages())
.thenReturn(Collections.emptyMap());

JsonObject stats = getBasicStats();
stats.getObject(PACKAGE_JSON_DEPENDENCIES).put("@vaadin/router",
"1.7.5");

setupFrontendUtilsMock(stats);

Mockito.when(
finder.getAnnotatedClasses(LoadDependenciesOnStartup.class))
.thenReturn(Collections.singleton(AllEagerAppConf.class));

final boolean needsBuild = BundleValidationUtil.needsBuild(options,
depScanner, finder, mode);
Assert.assertTrue(
"'LoadDependenciesOnStartup' annotation requires build",
needsBuild);
}

Expand Down Expand Up @@ -587,8 +623,7 @@ public void packageJsonHasOldPlatformDependencies_statsDoesNotHaveThem_noCompila
}

@Test
public void noPackageJson_defaultPackagesAndModulesInStats_noBuildNeeded()
throws IOException {
public void noPackageJson_defaultPackagesAndModulesInStats_noBuildNeeded() {
final FrontendDependenciesScanner depScanner = Mockito
.mock(FrontendDependenciesScanner.class);
Mockito.when(depScanner.getPackages())
Expand All @@ -614,8 +649,7 @@ public void noPackageJson_defaultPackagesAndModulesInStats_noBuildNeeded()
}

@Test
public void noPackageJson_defaultPackagesInStats_missingNpmModules_buildNeeded()
throws IOException {
public void noPackageJson_defaultPackagesInStats_missingNpmModules_buildNeeded() {
final FrontendDependenciesScanner depScanner = Mockito
.mock(FrontendDependenciesScanner.class);
Mockito.when(depScanner.getPackages())
Expand All @@ -641,8 +675,7 @@ public void noPackageJson_defaultPackagesInStats_missingNpmModules_buildNeeded()
}

@Test
public void noPackageJson_defaultPackagesInStats_noBuildNeeded()
throws IOException {
public void noPackageJson_defaultPackagesInStats_noBuildNeeded() {
final FrontendDependenciesScanner depScanner = Mockito
.mock(FrontendDependenciesScanner.class);
Mockito.when(depScanner.getPackages())
Expand Down Expand Up @@ -1650,20 +1683,28 @@ private void createProjectFrontendFileStub() throws IOException {
}

private void setupFrontendUtilsMock(JsonObject stats) {
devBundleUtils
.when(() -> DevBundleUtils.getDevBundleFolder(Mockito.any()))
.thenReturn(temporaryFolder.getRoot());
devBundleUtils
.when(() -> DevBundleUtils
.findBundleStatsJson(temporaryFolder.getRoot()))
.thenAnswer(q -> stats.toJson());
if (mode == Mode.PRODUCTION) {
bundleUtils
.when(() -> BundleValidationUtil.findProdBundleStatsJson(
Mockito.any(ClassFinder.class)))
.thenReturn(stats.toJson());
} else {
devBundleUtils.when(
() -> DevBundleUtils.getDevBundleFolder(Mockito.any()))
.thenReturn(temporaryFolder.getRoot());
devBundleUtils
.when(() -> DevBundleUtils
.findBundleStatsJson(temporaryFolder.getRoot()))
.thenAnswer(q -> stats.toJson());
}
frontendUtils
.when(() -> FrontendUtils.getJarResourceString(
Mockito.anyString(), Mockito.any(ClassFinder.class)))
.thenAnswer(q -> jarResources.get(q.getArgument(0)));
bundleUtils
.when(() -> BundleValidationUtil.findProdBundleStatsJson(
Mockito.any(ClassFinder.class)))
.thenReturn(stats.toJson());
}

@LoadDependenciesOnStartup
static class AllEagerAppConf implements AppShellConfigurator {

}
}

0 comments on commit 683df7f

Please sign in to comment.