Skip to content

Commit 8c2655d

Browse files
authored
fix: move import statements to top in generated web component imports file (#23817) (CP: 25.0) (#23820)
This PR cherry-picks changes from the original PR #23817 to branch 25.0. --- #### Original PR description > `AbstractUpdateImports.process()` already reorders `import` lines to > the top for `generatedFlowImports`, but the same sorting was not > applied to `generatedFlowWebComponentImports`. This caused interleaved > `import` and non-import lines (e.g. `injectGlobalWebcomponentCss()` > calls mixed with `import` statements) in the web component output. > > Extract a reusable `moveImportsToTop()` method and apply it both in > `process()` for main imports and in `mergeWebComponentOutputLines()` > after merging and deduplicating the web component sources. > > Related to #23689 (comment)
1 parent b021a69 commit 8c2655d

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

flow-server/src/main/java/com/vaadin/flow/server/frontend/AbstractUpdateImports.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,18 @@ private List<String> mergeWebComponentOutputLines(
267267
Collections.emptyList()));
268268
merged.addAll(outputFiles.getOrDefault(generatedFlowImports,
269269
Collections.emptyList()));
270-
return merged.stream().distinct().toList();
270+
List<String> result = new ArrayList<>(
271+
merged.stream().distinct().toList());
272+
moveImportsToTop(result);
273+
return result;
274+
}
275+
276+
// Move all import lines to the top, before any non-import lines
277+
private static void moveImportsToTop(List<String> lines) {
278+
List<String> imports = new ArrayList<>(lines);
279+
imports.removeIf(line -> !line.startsWith("import "));
280+
lines.removeIf(line -> line.startsWith("import "));
281+
lines.addAll(0, imports);
271282
}
272283

273284
private void writeWebComponentImports(List<String> lines) {
@@ -441,11 +452,7 @@ private Map<File, List<String>> process(Map<ChunkInfo, List<CssData>> css,
441452
getCssLines(webComponentCssData, cssLineOffset));
442453
}
443454

444-
// Move all imports to the top
445-
List<String> copy = new ArrayList<>(mainLines);
446-
copy.removeIf(line -> !line.startsWith("import "));
447-
mainLines.removeIf(line -> line.startsWith("import "));
448-
mainLines.addAll(0, copy);
455+
moveImportsToTop(mainLines);
449456

450457
mainLines.addAll(chunkLoader);
451458
mainLines.add("window.Vaadin = window.Vaadin || {};");

flow-server/src/test/java/com/vaadin/flow/server/frontend/AbstractUpdateImportsTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@
4848
import com.vaadin.experimental.FeatureFlags;
4949
import com.vaadin.flow.component.Component;
5050
import com.vaadin.flow.component.UI;
51+
import com.vaadin.flow.component.WebComponentExporter;
5152
import com.vaadin.flow.component.dependency.CssImport;
5253
import com.vaadin.flow.component.dependency.JavaScript;
5354
import com.vaadin.flow.component.dependency.JsModule;
5455
import com.vaadin.flow.component.page.AppShellConfigurator;
56+
import com.vaadin.flow.component.webcomponent.WebComponent;
5557
import com.vaadin.flow.router.Route;
5658
import com.vaadin.flow.server.Constants;
5759
import com.vaadin.flow.server.LoadDependenciesOnStartup;
@@ -108,6 +110,19 @@ public static class FooCssImport2 extends Component {
108110
public static class ThemeCssImport implements AppShellConfigurator {
109111
}
110112

113+
@CssImport("./foo.css")
114+
public static class CssImportExporter
115+
extends WebComponentExporter<FooCssImport> {
116+
public CssImportExporter() {
117+
super("css-import-exporter");
118+
}
119+
120+
@Override
121+
public void configureInstance(WebComponent<FooCssImport> webComponent,
122+
FooCssImport component) {
123+
}
124+
}
125+
111126
protected File tmpRoot;
112127
protected File frontendDirectory;
113128
protected File nodeModulesPath;
@@ -876,4 +891,45 @@ private void assertImportOrder(String... imports) {
876891
}
877892
}
878893

894+
@Test
895+
public void generatedFlowImports_importsAreOnTopBeforeOtherInstructions() {
896+
updater.run();
897+
898+
List<String> lines = updater.getOutput()
899+
.get(updater.generatedFlowImports);
900+
assertImportsBeforeNonImportLines(lines);
901+
}
902+
903+
@Test
904+
public void generatedFlowWebComponentImports_importsAreOnTopBeforeOtherInstructions()
905+
throws Exception {
906+
Class<?>[] testClasses = { CssImportExporter.class, FooCssImport.class,
907+
UI.class, AllEagerAppConf.class };
908+
ClassFinder classFinder = getClassFinder(testClasses);
909+
updater = new UpdateImports(getScanner(classFinder), options);
910+
updater.run();
911+
912+
List<String> lines = updater.webComponentImports;
913+
Assert.assertNotNull("Web component imports should have been generated",
914+
lines);
915+
assertImportsBeforeNonImportLines(lines);
916+
}
917+
918+
private void assertImportsBeforeNonImportLines(List<String> lines) {
919+
boolean seenNonImport = false;
920+
for (String line : lines) {
921+
if (line.isBlank()) {
922+
continue;
923+
}
924+
if (!line.startsWith("import ")) {
925+
seenNonImport = true;
926+
} else if (seenNonImport) {
927+
Assert.fail("Import line found after non-import line. "
928+
+ "All import lines should be at the top.\n"
929+
+ "Offending line: " + line + "\n" + "Full output:\n"
930+
+ String.join("\n", lines));
931+
}
932+
}
933+
}
934+
879935
}

0 commit comments

Comments
 (0)