Skip to content

Commit 3229268

Browse files
authored
feat: Add clean-frontend goal to maven plugin (#11968)
Add a goal to clean frontend files handled by the framework. Most files are removed, but package.json is only cleaned of framework managed changes. Fixes #8885
1 parent 99fad4f commit 3229268

File tree

3 files changed

+458
-0
lines changed

3 files changed

+458
-0
lines changed
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright 2000-2021 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.plugin.maven;
17+
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.HashSet;
22+
import java.util.Set;
23+
24+
import org.apache.commons.io.FileUtils;
25+
import org.apache.maven.plugin.MojoFailureException;
26+
import org.apache.maven.plugins.annotations.LifecyclePhase;
27+
import org.apache.maven.plugins.annotations.Mojo;
28+
29+
import elemental.json.Json;
30+
import elemental.json.JsonObject;
31+
import elemental.json.impl.JsonUtil;
32+
33+
/**
34+
* Goal that cleans the frontend files to a clean state.
35+
* <p>
36+
* Deletes Vaadin dependencies from package.json, the generated frontend folder
37+
* and the npm/pnpm-related files and folders:
38+
* <ul>
39+
* <li>node_modules
40+
* <li>pnpm-lock.yaml
41+
* <li>package-lock.json
42+
* </ul>
43+
*
44+
* @since 9.0
45+
*/
46+
@Mojo(name = "clean-frontend", defaultPhase = LifecyclePhase.CLEAN)
47+
public class CleanFrontendMojo extends FlowModeAbstractMojo {
48+
49+
public static final String VAADIN = "vaadin";
50+
public static final String DEPENDENCIES = "dependencies";
51+
public static final String DEV_DEPENDENCIES = "devDependencies";
52+
53+
@Override
54+
public void execute() throws MojoFailureException {
55+
removeNodeModules();
56+
57+
// Cleanup (p)npm lock file.
58+
File lockFile = new File(npmFolder(), "pnpm-lock.yaml");
59+
if (!lockFile.exists()) {
60+
lockFile = new File(npmFolder(), "package-lock.json");
61+
}
62+
if (lockFile.exists()) {
63+
lockFile.delete();
64+
}
65+
66+
// clean up generated files from frontend
67+
if (generatedTsFolder().exists()) {
68+
try {
69+
FileUtils.deleteDirectory(generatedTsFolder());
70+
} catch (IOException exception) {
71+
throw new MojoFailureException(
72+
"Failed to remove folder'"
73+
+ generatedTsFolder().getAbsolutePath() + "'",
74+
exception);
75+
}
76+
}
77+
78+
try {
79+
// Clean up package json framework managed versions.
80+
File packageJsonFile = new File(npmFolder(), "package.json");
81+
if (packageJsonFile.exists()) {
82+
JsonObject packageJson = Json.parse(FileUtils.readFileToString(
83+
packageJsonFile, StandardCharsets.UTF_8.name()));
84+
85+
cleanupPackage(packageJson);
86+
87+
FileUtils.write(packageJsonFile,
88+
JsonUtil.stringify(packageJson, 2) + "\n",
89+
StandardCharsets.UTF_8.name());
90+
}
91+
} catch (IOException e) {
92+
throw new MojoFailureException(
93+
"Failed to clean 'package.json' file", e);
94+
}
95+
}
96+
97+
/**
98+
* Try to remove the node_modules folder.
99+
* <p>
100+
* Log a warning if there was an issue removing the folder.
101+
*/
102+
private void removeNodeModules() {
103+
// Remove node_modules folder
104+
File nodeModules = new File(npmFolder(), "node_modules");
105+
if (nodeModules.exists()) {
106+
try {
107+
FileUtils.deleteDirectory(nodeModules);
108+
} catch (IOException exception) {
109+
getLog().debug("Exception removing node_modules", exception);
110+
getLog().error(
111+
"Failed to remove '" + nodeModules.getAbsolutePath()
112+
+ "'. Please remove it manually.");
113+
}
114+
}
115+
}
116+
117+
private void cleanupPackage(JsonObject packageJson) {
118+
JsonObject dependencies = packageJson.getObject(DEPENDENCIES);
119+
JsonObject devDependencies = packageJson.getObject(DEV_DEPENDENCIES);
120+
121+
if (packageJson.hasKey(VAADIN)) {
122+
JsonObject vaadin = packageJson.getObject(VAADIN);
123+
JsonObject vaadinDependencies = vaadin.getObject(DEPENDENCIES);
124+
JsonObject vaadinDevDependencies = vaadin
125+
.getObject(DEV_DEPENDENCIES);
126+
127+
// Remove all
128+
cleanObject(dependencies, vaadinDependencies);
129+
cleanObject(devDependencies, vaadinDevDependencies);
130+
packageJson.remove(VAADIN);
131+
}
132+
133+
cleanFrameworkBuildDependenices(dependencies);
134+
cleanFrameworkBuildDependenices(devDependencies);
135+
136+
// Remove the hash to get a npm install executed
137+
packageJson.remove("hash");
138+
139+
}
140+
141+
private void cleanObject(JsonObject target, JsonObject reference) {
142+
if (target == null) {
143+
return;
144+
}
145+
Set<String> removeKeys = new HashSet<>();
146+
147+
for (String key : target.keys()) {
148+
if (reference.hasKey(key)
149+
&& target.getString(key).equals(reference.getString(key))) {
150+
removeKeys.add(key);
151+
}
152+
}
153+
154+
for (String key : removeKeys) {
155+
target.remove(key);
156+
}
157+
}
158+
159+
/**
160+
* Clean any dependencies that target the build folder in the given json
161+
* object.
162+
* <p>
163+
* With default settings it would mean all starting with {@code ./target}.
164+
*
165+
* @param dependencyObject
166+
* json object to clean
167+
*/
168+
private void cleanFrameworkBuildDependenices(JsonObject dependencyObject) {
169+
if (dependencyObject == null) {
170+
return;
171+
}
172+
String buildTargetFolder = "./" + buildFolder();
173+
174+
Set<String> removeKeys = new HashSet<>();
175+
for (String key : dependencyObject.keys()) {
176+
if (dependencyObject.getString(key).startsWith(buildTargetFolder)) {
177+
removeKeys.add(key);
178+
}
179+
}
180+
181+
for (String key : removeKeys) {
182+
dependencyObject.remove(key);
183+
}
184+
}
185+
186+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2000-2021 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.plugin.maven;
17+
18+
import org.apache.maven.plugins.annotations.LifecyclePhase;
19+
import org.apache.maven.plugins.annotations.Mojo;
20+
21+
/**
22+
* This is the hidden `vaadin:dance` to clean up the frontend files.
23+
*
24+
* @since
25+
*/
26+
@Mojo(name = "dance", defaultPhase = LifecyclePhase.CLEAN)
27+
public class FrontendDanceMojo extends CleanFrontendMojo {
28+
}

0 commit comments

Comments
 (0)