Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for customizable projectFileExtensions #20397

Merged
merged 12 commits into from
Nov 11, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
Expand Down Expand Up @@ -464,6 +465,11 @@ public String applicationIdentifier() {
return project.getGroupId() + ":" + project.getArtifactId();
}

@Override
public List<String> frontendExtraFileExtensions() {
return Collections.emptyList();
}

@Override
public boolean checkRuntimeDependency(String groupId, String artifactId,
Consumer<String> missingDependencyMessageConsumer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,7 @@ internal class GradlePluginAdapter(
}
return dependencyAbsent
}

override fun frontendExtraFileExtensions(): List<String> =
config.frontendExtraFileExtensions.get()
}
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,13 @@ public abstract class VaadinFlowPluginExtension @Inject constructor(private val

public abstract val applicationIdentifier: Property<String>

/**
* The list of extra file extensions that are considered project files.
* Hashes are calculated for these files as part of detecting if a new prod
* bundle should be generated.
mcollovati marked this conversation as resolved.
Show resolved Hide resolved
*/
public abstract val frontendExtraFileExtensions: ListProperty<String>

public fun filterClasspath(@DelegatesTo(value = ClasspathFilter::class, strategy = Closure.DELEGATE_FIRST) block: Closure<*>) {
block.delegate = classpathFilter
block.resolveStrategy = Closure.DELEGATE_FIRST
Expand Down Expand Up @@ -439,6 +446,10 @@ public class PluginEffectiveConfiguration(
))
.overrideWithSystemProperty("vaadin.${InitParameters.APPLICATION_IDENTIFIER}")

// TODO: Possibly get value from system param InitParameters.FRONTEND_EXTRA_EXTENSIONS
public val frontendExtraFileExtensions: ListProperty<String> = extension.frontendExtraFileExtensions
.convention(emptyList())

/**
* Finds the value of a boolean property. It searches in gradle and system properties.
*
Expand Down Expand Up @@ -499,7 +510,8 @@ public class PluginEffectiveConfiguration(
"alwaysExecutePrepareFrontend=${alwaysExecutePrepareFrontend.get()}, " +
"frontendHotdeploy=${frontendHotdeploy.get()}," +
"reactEnable=${reactEnable.get()}," +
"cleanFrontendFiles=${cleanFrontendFiles.get()}" +
"cleanFrontendFiles=${cleanFrontendFiles.get()}," +
"frontendExtraFileExtensions=${frontendExtraFileExtensions.get()}" +
")"
public companion object {
public fun get(project: Project): PluginEffectiveConfiguration =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
Expand Down Expand Up @@ -234,6 +235,22 @@ public abstract class FlowModeAbstractMojo extends AbstractMojo
@Parameter(property = InitParameters.REACT_ENABLE, defaultValue = "${null}")
private Boolean reactEnable;

/**
* Parameter for adding file extensions to handle during frontend tasks.
* <p>
* From the commandline use comma separated list
* {@code -Ddevmode.frontendExtraFileExtensions="svg,ico"}
* <p>
* In plugin configuration use comma separated values
*
* <configuration>
* <frontendExtraFileExtensions>svg,ico</frontendExtraFileExtensions>
* </configuration>
*
*/
@Parameter(property = InitParameters.FRONTEND_EXTRA_EXTENSIONS, defaultValue = "${null}")
private List<String> frontendExtraFileExtensions;

/**
* Identifier for the application.
* <p>
Expand Down Expand Up @@ -570,4 +587,14 @@ public String applicationIdentifier() {
project.getGroupId() + ":" + project.getArtifactId(),
StandardCharsets.UTF_8);
}

@Override
public List<String> frontendExtraFileExtensions() {
if (frontendExtraFileExtensions != null) {
return frontendExtraFileExtensions;
}

return Collections.emptyList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
Expand Down Expand Up @@ -74,6 +75,7 @@
import static com.vaadin.flow.server.Constants.NPM_TOKEN;
import static com.vaadin.flow.server.Constants.PROJECT_FRONTEND_GENERATED_DIR_TOKEN;
import static com.vaadin.flow.server.InitParameters.APPLICATION_IDENTIFIER;
import static com.vaadin.flow.server.InitParameters.FRONTEND_EXTRA_EXTENSIONS;
import static com.vaadin.flow.server.InitParameters.FRONTEND_HOTDEPLOY;
import static com.vaadin.flow.server.InitParameters.NODE_DOWNLOAD_ROOT;
import static com.vaadin.flow.server.InitParameters.NODE_VERSION;
Expand Down Expand Up @@ -165,7 +167,9 @@ public static void prepareFrontend(PluginAdapterBase adapter)
.setNodeAutoUpdate(adapter.nodeAutoUpdate())
.withHomeNodeExecRequired(adapter.requireHomeNodeExec())
.setJavaResourceFolder(adapter.javaResourceFolder())
.withProductionMode(false).withReact(adapter.isReactEnabled());
.withProductionMode(false).withReact(adapter.isReactEnabled())
.withFrontendExtraFileExtensions(
adapter.frontendExtraFileExtensions());

// Copy jar artifact contents in TaskCopyFrontendFiles
options.copyResources(adapter.getJarFiles());
Expand Down Expand Up @@ -264,6 +268,12 @@ public static File propagateBuildInfo(PluginAdapterBase adapter) {

buildInfo.put(REACT_ENABLE, adapter.isReactEnabled());

if (!adapter.frontendExtraFileExtensions().isEmpty()) {
buildInfo.put(FRONTEND_EXTRA_EXTENSIONS,
adapter.frontendExtraFileExtensions().stream()
.collect(Collectors.joining(",")));
}

try {
FileUtils.forceMkdir(token.getParentFile());
FileIOUtils.writeIfChanged(token,
Expand Down Expand Up @@ -405,7 +415,9 @@ public static void runDevBuildNodeUpdater(PluginAdapterBuild adapter)
.withBundleBuild(true)
.skipDevBundleBuild(adapter.skipDevBundleBuild())
.withCompressBundle(adapter.compressBundle())
.withReact(adapter.isReactEnabled());
.withReact(adapter.isReactEnabled())
.withFrontendExtraFileExtensions(
adapter.frontendExtraFileExtensions());
new NodeTasks(options).execute();
} catch (ExecutionFailedException exception) {
throw exception;
Expand Down Expand Up @@ -739,6 +751,7 @@ public static void updateBuildFile(PluginAdapterBuild adapter,
buildInfo.remove(NODE_DOWNLOAD_ROOT);
buildInfo.remove(FRONTEND_TOKEN);
buildInfo.remove(FRONTEND_HOTDEPLOY);
buildInfo.remove(FRONTEND_EXTRA_EXTENSIONS);
buildInfo.remove(InitParameters.SERVLET_PARAMETER_ENABLE_PNPM);
buildInfo.remove(InitParameters.SERVLET_PARAMETER_ENABLE_BUN);
buildInfo.remove(InitParameters.CI_BUILD);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,14 @@ default Lookup createLookup(ClassFinder classFinder) {
* {@literal blank}.
*/
String applicationIdentifier();

/**
* Get the list of project file extensions.
* <p>
* File extensions are given with or without . prefix eg "png" and ".png"
* are both accepted.
*
* @return list of project file extensions
*/
List<String> frontendExtraFileExtensions();
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ public class InitParameters implements Serializable {
*/
public static final String APPLICATION_PARAMETER_DEVMODE_ENABLE_COMPONENT_TRACKER = "devmode.componentTracker.enabled";

/**
* Configuration parameter name for adding extra file extensions for stats
* bundle to generate hashes for.
*/
public static final String FRONTEND_EXTRA_EXTENSIONS = "devmode.frontendExtraFileExtensions";

/**
* I18N provider property.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand Down Expand Up @@ -84,6 +85,8 @@ public class Options implements Serializable {

private boolean compressBundle = true;

private List<String> frontendExtraFileExtensions = null;

/**
* The node.js version to be used when node.js is installed automatically by
* Vaadin, for example <code>"v16.0.0"</code>. Defaults to
Expand Down Expand Up @@ -967,4 +970,26 @@ public Options withCleanOldGeneratedFiles(boolean clean) {
public boolean isCleanOldGeneratedFiles() {
return cleanOldGeneratedFiles;
}

/**
* Sets the extra file extensions used in the project.
*
* @param frontendExtraFileExtensions
* the file extensions to add for the project
* @return this builder
*/
public Options withFrontendExtraFileExtensions(
List<String> frontendExtraFileExtensions) {
this.frontendExtraFileExtensions = frontendExtraFileExtensions;
return this;
}

/**
* Gets the project file extensions.
*
* @return the project file extensions
*/
public List<String> getFrontendExtraFileExtensions() {
return frontendExtraFileExtensions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
Expand Down Expand Up @@ -118,6 +122,8 @@ private void createGeneratedConfig() throws IOException {
.getResource(FrontendUtils.VITE_GENERATED_CONFIG);
String template = IOUtils.toString(resource, StandardCharsets.UTF_8);

System.out.println(
"=== '" + options.getFrontendExtraFileExtensions() + "'");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
System.out.println(
"=== '" + options.getFrontendExtraFileExtensions() + "'");
System.out.println(
"=== '" + options.getFrontendExtraFileExtensions() + "'");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to push the removal =P

template = template
.replace("#settingsImport#",
"./" + options.getBuildDirectoryName() + "/"
Expand All @@ -127,14 +133,29 @@ private void createGeneratedConfig() throws IOException {
.replace("#webComponentTags#",
webComponentTags == null || webComponentTags.isEmpty()
? ""
: String.join(";", webComponentTags));
: String.join(";", webComponentTags))
.replace("#frontendExtraFileExtensions#",
getFrontendExtraFileExtensions());
template = updateFileSystemRouterVitePlugin(template);

FileIOUtils.writeIfChanged(generatedConfigFile, template);
log().debug("Created vite generated configuration file: '{}'",
generatedConfigFile);
}

private String getFrontendExtraFileExtensions() {
Optional<List<String>> frontendExtraFileExtensions = Optional
.ofNullable(options.getFrontendExtraFileExtensions());
if (frontendExtraFileExtensions.isPresent()
&& frontendExtraFileExtensions.get().size() > 0) {
return frontendExtraFileExtensions.get().stream()
.map(ext -> ext.replace("'", "\\'"))
.map(ext -> ext.startsWith(".") ? ext : "." + ext)
mcollovati marked this conversation as resolved.
Show resolved Hide resolved
.collect(Collectors.joining("', '", ", '", "'"));
}
return "";
}

private String updateFileSystemRouterVitePlugin(String template) {
if (options.isReactEnabled() && FrontendUtils.isHillaUsed(
options.getFrontendDirectory(), options.getClassFinder())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ protected Map<String, String> getConfigParametersUsingTokenData(
String.valueOf(buildInfo.getBoolean(PREMIUM_FEATURES)));
}

if (buildInfo.hasKey(InitParameters.FRONTEND_EXTRA_EXTENSIONS)) {
params.put(InitParameters.FRONTEND_EXTRA_EXTENSIONS, buildInfo
.getString(InitParameters.FRONTEND_EXTRA_EXTENSIONS));
}

setDevModePropertiesUsingTokenData(params, buildInfo);
return params;
}
Expand Down
2 changes: 1 addition & 1 deletion flow-server/src/main/resources/vite.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ function statsExtracterPlugin(): PluginOption {

const frontendFiles: Record<string, string> = {};

const projectFileExtensions = ['.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map'];
const projectFileExtensions = ['.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map'#frontendExtraFileExtensions#];

const isThemeComponentsResource = (id: string) =>
id.startsWith(themeOptions.frontendGeneratedFolder.replace(/\\/g, '/'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ public void createInitParameters_valuesAreTakenFromservletConfigAndTokenFile_val
InitParameters.COMPILED_WEB_COMPONENTS_PATH,
InitParameters.NODE_VERSION, InitParameters.NODE_DOWNLOAD_ROOT,
InitParameters.BUILD_FOLDER,
InitParameters.APPLICATION_IDENTIFIER));
InitParameters.APPLICATION_IDENTIFIER,
InitParameters.FRONTEND_EXTRA_EXTENSIONS));
Field[] initParamFields = InitParameters.class.getDeclaredFields();
String mockTokenJsonString = generateJsonStringFromFields(
initParamFields, stringParams);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -174,4 +175,48 @@ public void generatedTemplate_reactDisabled_correctFileRouterImport()
template.contains(", vitePluginFileSystemRouter()"));

}

@Test
public void generatedTemplate_extraFrontendExtension_addedToViteConfiguration()
throws IOException {
options.withFrontendExtraFileExtensions(
Arrays.asList(".svg", ".ico", "png"));
TaskUpdateVite task = new TaskUpdateVite(options, null);
task.execute();

File configFile = new File(temporaryFolder.getRoot(),
FrontendUtils.VITE_GENERATED_CONFIG);

String template = IOUtils.toString(configFile.toURI(),
StandardCharsets.UTF_8);
Pattern matchSelection = Pattern
.compile("const projectFileExtensions = \\[(.*)];");
Matcher matcher = matchSelection.matcher(template);
Assert.assertTrue("No projectFileExtensions found", matcher.find());
Assert.assertEquals(
"Extra frontend extensions should be added to vite configuration, but was not.",
"'.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map', '.svg', '.ico', '.png'",
matcher.group(1));
}

@Test
public void generatedTemplate_noEraFrontendExtension_viteConfigurationWithoutExtraSelections()
throws IOException {
TaskUpdateVite task = new TaskUpdateVite(options, null);
task.execute();

File configFile = new File(temporaryFolder.getRoot(),
FrontendUtils.VITE_GENERATED_CONFIG);

String template = IOUtils.toString(configFile.toURI(),
StandardCharsets.UTF_8);
Pattern matchSelection = Pattern
.compile("const projectFileExtensions = \\[(.*)];");
Matcher matcher = matchSelection.matcher(template);
Assert.assertTrue("No projectFileExtensions found", matcher.find());
Assert.assertEquals(
"Extra frontend extensions should be added to vite configuration, but was not.",
"'.js', '.js.map', '.ts', '.ts.map', '.tsx', '.tsx.map', '.css', '.css.map'",
matcher.group(1));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
</goals>
</execution>
</executions>
<configuration>
<frontendExtraFileExtensions>scss</frontendExtraFileExtensions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
p {
border: 3px solid orange;
}
Loading
Loading