From fb7b6cf01a567e4eeb699802ebd8911c12325070 Mon Sep 17 00:00:00 2001 From: Tomi Virtanen Date: Fri, 22 May 2026 14:08:56 +0300 Subject: [PATCH 1/2] feat: add npm.excludePostinstallPackages option Adds a configuration option to exclude packages from running postinstall scripts. Mirrors the existing npm.postinstallPackages add-list and applies to both the built-in default entries (e.g. esbuild, @vaadin/vaadin-usage-statistics) and any packages added via postinstallPackages. Wired through Options, the Maven and Gradle plugins, and DevModeInitializer. Refs #24333 --- .../vaadin/flow/server/frontend/Options.java | 26 +++++++++++++++++++ .../server/frontend/TaskRunNpmInstall.java | 1 + .../frontend/TaskRunPnpmInstallTest.java | 17 ++++++++++++ .../flow/plugin/maven/BuildDevBundleMojo.java | 14 ++++++++++ .../com/vaadin/gradle/GradlePluginAdapter.kt | 3 +++ .../gradle/PrepareFrontendInputProperties.kt | 4 +++ .../gradle/VaadinFlowPluginExtension.kt | 12 +++++++++ .../plugin/maven/FlowModeAbstractMojo.java | 14 ++++++++++ .../flow/plugin/base/BuildFrontendUtil.java | 4 +++ .../flow/plugin/base/PluginAdapterBase.java | 9 +++++++ .../vaadin/flow/server/InitParameters.java | 7 +++++ .../devserver/startup/DevModeInitializer.java | 5 ++++ 12 files changed, 116 insertions(+) diff --git a/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/Options.java b/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/Options.java index 524e45e824e..970506bffc2 100644 --- a/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/Options.java +++ b/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/Options.java @@ -148,6 +148,11 @@ public class Options implements Serializable { */ private List postinstallPackages = new ArrayList<>(); + /** + * Npm packages to exclude from running postinstall scripts. + */ + private List excludePostinstallPackages = new ArrayList<>(); + private FeatureFlags featureFlags; private boolean frontendHotdeploy = false; @@ -698,6 +703,23 @@ public Options withPostinstallPackages(List postinstallPackages) { return this; } + /** + * Sets the npm packages to exclude from running {@code postinstall} for. + *

+ * Entries here are removed from the built-in default postinstall list (e.g. + * {@code esbuild}, {@code @vaadin/vaadin-usage-statistics}) as well as from + * any additional packages added via {@link #withPostinstallPackages(List)}. + * + * @param excludePostinstallPackages + * the npm packages to exclude from postinstall + * @return the builder, for chaining + */ + public Options withExcludePostinstallPackages( + List excludePostinstallPackages) { + this.excludePostinstallPackages = excludePostinstallPackages; + return this; + } + /** * Get the npm folder used for this build. * @@ -925,6 +947,10 @@ public List getPostinstallPackages() { return postinstallPackages; } + public List getExcludePostinstallPackages() { + return excludePostinstallPackages; + } + /** * Set to true to skip dev bundle build in case a dev bundle exists. *

diff --git a/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/TaskRunNpmInstall.java b/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/TaskRunNpmInstall.java index 12e018a9ec0..4cd1232b675 100644 --- a/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/TaskRunNpmInstall.java +++ b/flow-build-tools/src/main/java/com/vaadin/flow/server/frontend/TaskRunNpmInstall.java @@ -382,6 +382,7 @@ private void runNpmInstall() throws ExecutionFailedException { postinstallPackages.add("esbuild"); postinstallPackages.add("@vaadin/vaadin-usage-statistics"); postinstallPackages.addAll(options.getPostinstallPackages()); + postinstallPackages.removeAll(options.getExcludePostinstallPackages()); for (String postinstallPackage : postinstallPackages) { File packageJsonFile = getPackageJsonForModule(postinstallPackage); diff --git a/flow-build-tools/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java b/flow-build-tools/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java index 7b125a1ba96..7fa1a07838f 100644 --- a/flow-build-tools/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java +++ b/flow-build-tools/src/test/java/com/vaadin/flow/server/frontend/TaskRunPnpmInstallTest.java @@ -345,6 +345,23 @@ void runPnpmInstall_postInstall_runForDefinedAdditionalPackages() "Postinstall for 'foo' was not run"); } + @Test + void runPnpmInstall_postInstall_excludedBuiltinPackageIsSkipped() + throws ExecutionFailedException, IOException { + setupPostinstallPackages(); + options.withExcludePostinstallPackages( + List.of("@vaadin/vaadin-usage-statistics")); + TaskRunNpmInstall task = createTask(); + task.execute(); + + assertFalse( + new File( + new File(options.getNodeModulesFolder(), + "@vaadin/vaadin-usage-statistics"), + "postinstall-file.txt").exists(), + "Postinstall for '@vaadin/vaadin-usage-statistics' should have been skipped"); + } + // https://github.com/vaadin/flow/issues/17663 @Test @Timeout(30) diff --git a/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java b/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java index 69a160f0f8f..cb0a5744136 100644 --- a/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java +++ b/flow-plugins/flow-dev-bundle-plugin/src/main/java/com/vaadin/flow/plugin/maven/BuildDevBundleMojo.java @@ -183,6 +183,15 @@ public class BuildDevBundleMojo extends AbstractMojo @Parameter(property = "npm.postinstallPackages", defaultValue = "") private List postinstallPackages; + /** + * Npm packages to exclude from running post install scripts. + *

+ * Used to skip built-in entries (e.g. {@code esbuild}) when their + * postinstall step is known to fail or is not needed. + */ + @Parameter(property = "npm.excludePostinstallPackages", defaultValue = "") + private List excludePostinstallPackages; + @Parameter(property = InitParameters.REACT_ENABLE, defaultValue = "true") private boolean reactEnable; @@ -516,6 +525,11 @@ public List postinstallPackages() { return postinstallPackages; } + @Override + public List excludePostinstallPackages() { + return excludePostinstallPackages; + } + @Override public boolean isFrontendHotdeploy() { return false; diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt index 4aa91aacb15..43170b4c40f 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/GradlePluginAdapter.kt @@ -276,6 +276,9 @@ internal class GradlePluginAdapter private constructor( override fun postinstallPackages(): List = config.postinstallPackages.get() + override fun excludePostinstallPackages(): List = + config.excludePostinstallPackages.get() + override fun isFrontendHotdeploy(): Boolean = config.frontendHotdeploy.get() override fun ciBuild(): Boolean = config.ciBuild.get() diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt index 181f256f627..9982f0d3a92 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/PrepareFrontendInputProperties.kt @@ -141,6 +141,10 @@ internal class PrepareFrontendInputProperties( fun getPostInstallPackages(): ListProperty = config.postinstallPackages + @Input + fun getExcludePostInstallPackages(): ListProperty = + config.excludePostinstallPackages + @Input fun getFrontendHotdeploy(): Provider = config.frontendHotdeploy diff --git a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt index 4eafb53fa8e..8f2986680c4 100644 --- a/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt +++ b/flow-plugins/flow-gradle-plugin/src/main/kotlin/com/vaadin/gradle/VaadinFlowPluginExtension.kt @@ -236,6 +236,13 @@ public abstract class VaadinFlowPluginExtension @Inject constructor(private val */ public abstract val postinstallPackages: ListProperty + /** + * Defines the npm packages to exclude from running postinstall scripts. + * Used to skip built-in entries (e.g. `esbuild`) when their postinstall + * step is known to fail or is not needed. + */ + public abstract val excludePostinstallPackages: ListProperty + public val classpathFilter: ClasspathFilter = ClasspathFilter() /** @@ -568,6 +575,10 @@ public class PluginEffectiveConfiguration( extension.postinstallPackages .convention(listOf()) + public val excludePostinstallPackages: ListProperty = + extension.excludePostinstallPackages + .convention(listOf()) + public val classpathFilter: ClasspathFilter = extension.classpathFilter public val processResourcesTaskName: Property = @@ -744,6 +755,7 @@ public class PluginEffectiveConfiguration( "resourceOutputDirectory=${resourceOutputDirectory.get()}, " + "projectBuildDir=${projectBuildDir.get()}, " + "postinstallPackages=${postinstallPackages.get()}, " + + "excludePostinstallPackages=${excludePostinstallPackages.get()}, " + "sourceSetName=${sourceSetName.get()}, " + "dependencyScope=${dependencyScope.get()}, " + "processResourcesTaskName=${processResourcesTaskName.get()}, " + diff --git a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java index f8350198359..e370ccadb64 100644 --- a/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java +++ b/flow-plugins/flow-maven-plugin/src/main/java/com/vaadin/flow/plugin/maven/FlowModeAbstractMojo.java @@ -256,6 +256,15 @@ public abstract class FlowModeAbstractMojo extends AbstractMojo @Parameter(property = "vaadin.npm.postinstallPackages", defaultValue = "") private List postinstallPackages; + /** + * Npm packages to exclude from running post install scripts. + *

+ * Used to skip built-in entries (e.g. {@code esbuild}) when their + * postinstall step is known to fail or is not needed. + */ + @Parameter(property = "vaadin.npm.excludePostinstallPackages", defaultValue = "") + private List excludePostinstallPackages; + /** * Parameter to control if frontend development server should be used in * development mode or not. @@ -710,6 +719,11 @@ public List postinstallPackages() { return postinstallPackages; } + @Override + public List excludePostinstallPackages() { + return excludePostinstallPackages; + } + @Override public boolean isFrontendHotdeploy() { if (frontendHotdeploy != null) { diff --git a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java index ec66bc8d1f8..53620414fd3 100644 --- a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java +++ b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/BuildFrontendUtil.java @@ -363,6 +363,8 @@ public static void runNodeUpdater(PluginAdapterBuild adapter, .withNodeDownloadRoot(nodeDownloadRootURI) .setJavaResourceFolder(adapter.javaResourceFolder()) .withPostinstallPackages(adapter.postinstallPackages()) + .withExcludePostinstallPackages( + adapter.excludePostinstallPackages()) .withCiBuild(adapter.ciBuild()) .withForceProductionBuild(adapter.forceProductionBuild()) .withReact(adapter.isReactEnabled()) @@ -440,6 +442,8 @@ public static void runDevBuildNodeUpdater(PluginAdapterBuild adapter) .withNodeDownloadRoot(nodeDownloadRootURI) .setJavaResourceFolder(adapter.javaResourceFolder()) .withPostinstallPackages(adapter.postinstallPackages()) + .withExcludePostinstallPackages( + adapter.excludePostinstallPackages()) .withBundleBuild(true) .skipDevBundleBuild(adapter.skipDevBundleBuild()) .withCompressBundle(adapter.compressBundle()) diff --git a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java index 58085ba5acf..d54afe43c37 100644 --- a/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java +++ b/flow-plugins/flow-plugin-base/src/main/java/com/vaadin/flow/plugin/base/PluginAdapterBase.java @@ -310,6 +310,15 @@ default File frontendOutputDirectory() { */ List postinstallPackages(); + /** + * Npm packages to exclude from running postinstall scripts. Removes + * matching entries from the built-in defaults and from any packages added + * via {@link #postinstallPackages()}. + * + * @return a list of packages to exclude + */ + List excludePostinstallPackages(); + boolean isFrontendHotdeploy(); /** diff --git a/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java b/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java index e24cfb45cef..9e2fd1f525e 100644 --- a/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java +++ b/flow-server/src/main/java/com/vaadin/flow/server/InitParameters.java @@ -234,6 +234,13 @@ public class InitParameters implements Serializable { */ public static final String ADDITIONAL_POSTINSTALL_PACKAGES = "npm.postinstallPackages"; + /** + * Packages to exclude from running postinstall scripts. Used to skip + * built-in entries (e.g. {@code esbuild}) when their postinstall step is + * known to fail or is not needed. + */ + public static final String EXCLUDE_POSTINSTALL_PACKAGES = "npm.excludePostinstallPackages"; + /** * Configuration name for enabling development using the frontend * development server instead of using an application bundle. diff --git a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java index 2042b81bd5c..b4a36fe4067 100644 --- a/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java +++ b/vaadin-dev-server/src/main/java/com/vaadin/base/devserver/startup/DevModeInitializer.java @@ -273,6 +273,9 @@ public static DevModeHandler initDevModeHandler(Set> classes, InitParameters.ADDITIONAL_POSTINSTALL_PACKAGES, "") .split(","); + String[] excludePostinstallPackages = config.getStringProperty( + InitParameters.EXCLUDE_POSTINSTALL_PACKAGES, "").split(","); + String frontendGeneratedFolderName = config.getStringProperty( PROJECT_FRONTEND_GENERATED_DIR_TOKEN, Paths.get(frontendFolder.getPath(), FrontendUtils.GENERATED) @@ -303,6 +306,8 @@ public static DevModeHandler initDevModeHandler(Set> classes, .withProductionMode(config.isProductionMode()) .withPostinstallPackages( Arrays.asList(additionalPostinstallPackages)) + .withExcludePostinstallPackages( + Arrays.asList(excludePostinstallPackages)) .withFrontendHotdeploy( mode == Mode.DEVELOPMENT_FRONTEND_LIVERELOAD) .withBundleBuild(mode == Mode.DEVELOPMENT_BUNDLE) From f3c35811f5601af801f2a3ae54e420fc545211f4 Mon Sep 17 00:00:00 2001 From: Tomi Virtanen Date: Fri, 22 May 2026 14:48:38 +0300 Subject: [PATCH 2/2] chore: add empty list to excludePostinstallPackages --- .../com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java b/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java index c1c46631118..bd819380f17 100644 --- a/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java +++ b/flow-plugins/flow-maven-plugin/src/test/java/com/vaadin/flow/plugin/maven/BuildFrontendMojoTest.java @@ -199,6 +199,8 @@ void setup() throws Exception { Paths.get(projectBase.toString(), "target").toString()); ReflectionUtils.setVariableValueInObject(mojo, "postinstallPackages", Collections.emptyList()); + ReflectionUtils.setVariableValueInObject(mojo, + "excludePostinstallPackages", Collections.emptyList()); Mockito.doReturn( Set.of(jarResourcesSource.getParentFile().getParentFile())) .when(mojo).getJarFiles();