diff --git a/core/pom.xml b/core/pom.xml
index 370bd946..113ff2a0 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -12,11 +12,121 @@
Small wrapper around esbuild to be able to use it in Java
- 0.0.9
- 0.23.0-mvnpm-${esbuild.mvnpm-build.version}
+ 0.23.1
+ 3.3.1
+ 1.89.1
+ 5.1.2
+ 0.4.2
+
+ org.mvnpm
+ esbuild
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ linux-x64
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ linux-arm
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ linux-ia32
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ win32-x64
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ win32-ia32
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ darwin-arm64
+ ${esbuild.version}
+ provided
+
+
+ org.mvnpm.at.esbuild
+ darwin-x64
+ ${esbuild.version}
+ provided
+
+
+
+ org.mvnpm
+ esbuild-sass-plugin
+ ${esbuild-sass-plugin.version}
+ provided
+
+
+ org.mvnpm
+ safe-identifier
+ ${safe-identifier.version}
+ provided
+
+
+ org.mvnpm
+ sass
+ ${sass.version}
+ provided
+
+
+ org.mvnpm
+ immutable
+ ${immutable.version}
+ provided
+
+
+
+ com.caoccao.javet
+ javet
+ 4.1.3
+
+
+
+ com.caoccao.javet
+ javet-node-linux-x86_64
+ 4.1.3
+
+
+
+ com.caoccao.javet
+ javet-node-linux-arm64
+ 4.1.3
+
+
+ com.caoccao.javet
+ javet-node-macos-x86_64
+ 4.1.3
+
+
+ com.caoccao.javet
+ javet-node-macos-arm64
+ 4.1.3
+
+
+ com.caoccao.javet
+ javet-node-windows-x86_64
+ 4.1.3
+
+
io.mvnpm
importmap
@@ -51,7 +161,7 @@
src/main/resources
- false
+ true
src/main/resources-filtered
diff --git a/core/src/main/java/io/mvnpm/esbuild/Bundler.java b/core/src/main/java/io/mvnpm/esbuild/Bundler.java
index 9e76cff4..1a34e2a3 100644
--- a/core/src/main/java/io/mvnpm/esbuild/Bundler.java
+++ b/core/src/main/java/io/mvnpm/esbuild/Bundler.java
@@ -13,7 +13,6 @@
import io.mvnpm.esbuild.install.WebDepsInstaller;
import io.mvnpm.esbuild.model.*;
-import io.mvnpm.esbuild.resolve.Resolver;
public class Bundler {
private static final Logger logger = Logger.getLogger(Bundler.class.getName());
@@ -124,9 +123,6 @@ protected static ExecuteResult esBuild(Path workDir, EsBuildConfig esBuildConfig
}
private static Execute getExecute(Path workDir, EsBuildConfig esBuildConfig) throws IOException {
- final String version = esBuildConfig.esBuildVersion() != null ? esBuildConfig.esBuildVersion()
- : Bundler.ESBUILD_EMBEDDED_VERSION;
- final Path esBuildExec = Resolver.create().resolve(version);
- return new Execute(workDir, esBuildExec.toFile(), esBuildConfig);
+ return new Execute(workDir, esBuildConfig);
}
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/Execute.java b/core/src/main/java/io/mvnpm/esbuild/Execute.java
index 3a82410e..7f9bf180 100644
--- a/core/src/main/java/io/mvnpm/esbuild/Execute.java
+++ b/core/src/main/java/io/mvnpm/esbuild/Execute.java
@@ -1,26 +1,29 @@
package io.mvnpm.esbuild;
-import java.io.*;
+import static io.mvnpm.esbuild.install.BuildDependency.getDependencies;
+
+import java.io.File;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
+import java.util.Scanner;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
-import java.util.logging.Level;
import java.util.logging.Logger;
+import com.caoccao.javet.exceptions.JavetException;
+import com.caoccao.javet.interop.NodeRuntime;
+import com.caoccao.javet.interop.V8Host;
+import com.caoccao.javet.interop.converters.JavetProxyConverter;
+
+import io.mvnpm.esbuild.install.WebDepsInstaller;
import io.mvnpm.esbuild.model.EsBuildConfig;
import io.mvnpm.esbuild.model.ExecuteResult;
import io.mvnpm.esbuild.model.WatchBuildResult;
import io.mvnpm.esbuild.model.WatchStartResult;
+import io.mvnpm.esbuild.util.EntryCreator;
public class Execute {
@@ -32,181 +35,132 @@ public class Execute {
private static final Logger logger = Logger.getLogger(Execute.class.getName());
private final Path workDir;
- private final File esBuildExec;
- private EsBuildConfig esBuildConfig;
- private String[] args;
+ private final EsBuildConfig esBuildConfig;
- public Execute(Path workDir, File esBuildExec, EsBuildConfig esBuildConfig) {
+ public Execute(Path workDir, EsBuildConfig esBuildConfig) {
this.workDir = workDir;
- this.esBuildExec = esBuildExec;
this.esBuildConfig = esBuildConfig;
}
- public Execute(Path workDir, File esBuildExec, String[] args) {
- this.workDir = workDir;
- this.esBuildExec = esBuildExec;
- this.args = args;
+ public ExecuteResult executeAndWait() throws IOException {
+ runBuild();
+ Path path = workDir.resolve(esBuildConfig.outdir() == null ? "." : esBuildConfig.outdir());
+ try (Scanner scanner = new Scanner(path, StandardCharsets.UTF_8)) {
+ String output = scanner.useDelimiter("\\A").hasNext() ? scanner.next() : "";
+ return new ExecuteResult(output);
+ }
}
- public ExecuteResult executeAndWait() throws IOException {
- final Process process = createProcess(getCommand(), Optional.empty());
- try {
- final int exitCode = process.waitFor();
- final String content = readStream(process.getInputStream());
- final String errors = readStream(process.getErrorStream());
- if (exitCode != 0) {
- throw new BundleException(errors.isEmpty() ? "Unexpected Error during bundling" : errors, content);
+ private void runBuild() throws IOException {
+ File entryJs = EntryCreator.createEntryJs(workDir, esBuildConfig);
+ WebDepsInstaller.install(workDir.resolve("node_modules"), getDependencies());
+
+ try (NodeRuntime nodeRuntime = V8Host.getNodeInstance().createV8Runtime()) {
+ nodeRuntime.allowEval(true);
+ try {
+ nodeRuntime.getExecutor(entryJs).executeVoid();
+ } catch (JavetException e) {
+ throw new RuntimeException(e);
}
- return new ExecuteResult(content);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
+ nodeRuntime.await();
+ } catch (JavetException e) {
throw new RuntimeException(e);
}
}
- public WatchStartResult watch(BuildEventListener listener) throws IOException {
- final Process process = createProcess(getCommand(), Optional.of(listener));
- final ExecutorService executorStreamer = Executors
- .newSingleThreadExecutor(r -> new Thread(r, "Esbuild watch stdout streamer"));
- final ExecutorService executorBuild = Executors
- .newSingleThreadExecutor(r -> new Thread(r, "Esbuild build listeners notify"));
- final AtomicReference result = new AtomicReference<>();
- CountDownLatch latch = new CountDownLatch(1);
- final WatchStartResult.WatchProcess watchProcess = new WatchStartResult.WatchProcess() {
- @Override
- public boolean isAlive() {
- return process.isAlive();
- }
-
- @Override
- public void close() throws IOException {
- process.destroyForcibly();
- executorStreamer.shutdownNow();
- executorBuild.shutdownNow();
- try {
- process.waitFor();
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(e);
+ private void runWatchBuild(BuildEventListener listener, CountDownLatch latch) throws IOException {
+ File entryJs = EntryCreator.createEntryJs(workDir, esBuildConfig);
+ WebDepsInstaller.install(workDir.resolve("node_modules"), getDependencies());
+
+ try (NodeRuntime nodeRuntime = V8Host.getNodeInstance().createV8Runtime()) {
+ nodeRuntime.setConverter(new JavetProxyConverter());
+ nodeRuntime.allowEval(true);
+
+ // Set up a JavaScript callback to handle build events
+ nodeRuntime.getGlobalObject().set("buildEventHandler", new BuildEventHandler() {
+ private boolean isFirstBuild = true;
+
+ @Override
+ public void onBuildComplete(String output) {
+ if (isFirstBuild) {
+ isFirstBuild = false;
+ latch.countDown();
+ } else {
+ listener.onBuild(new WatchBuildResult(output));
+ }
}
- if (latch.getCount() == 1) {
- latch.countDown();
- }
- }
- };
- try {
- final InputStream processStream = process.getInputStream();
- executorStreamer.execute(new Streamer(executorBuild, process::isAlive, processStream, (r) -> {
- if (latch.getCount() == 1) {
- result.set(r);
- latch.countDown();
- } else {
- listener.onBuild(r);
- }
- }, r -> {
- if (latch.getCount() == 1) {
- result.set(r);
- latch.countDown();
- } else if (!r.isSuccess()) {
- listener.onBuild(r);
+ @Override
+ public void onBuildError(String output, String error) {
+ if (isFirstBuild) {
+ isFirstBuild = false;
+ latch.countDown();
+ } else {
+ listener.onBuild(new WatchBuildResult(output, new BundleException(output, error)));
+ }
}
- }));
- latch.await();
- if (!process.isAlive() && !result.get().isSuccess()) {
- throw result.get().bundleException();
- }
+ });
- return new WatchStartResult(result.get(), watchProcess);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- watchProcess.close();
+ try {
+ nodeRuntime.getExecutor(entryJs).executeVoid();
+ } catch (JavetException e) {
+ throw new RuntimeException(e);
+ }
+ nodeRuntime.await();
+ } catch (JavetException e) {
throw new RuntimeException(e);
}
}
- private String[] getCommand() {
- String[] command = args != null ? getCommand(args) : getCommand(esBuildConfig);
- if (logger.isLoggable(Level.FINE)) {
- logger.log(Level.FINE, "running esbuild with flags: \n > `{0}`", String.join(" ", command));
- }
- return command;
- }
-
- private String[] getCommand(EsBuildConfig esBuildConfig) {
- String[] params = esBuildConfig.toParams();
- return getCommand(params);
- }
-
- private String[] getCommand(String[] args) {
- List argList = new ArrayList<>(args.length + 1);
- argList.add(esBuildExec.toString());
- argList.addAll(Arrays.asList(args));
+ public interface BuildEventHandler {
+ void onBuildComplete(String output);
- return argList.toArray(String[]::new);
+ void onBuildError(String output, String error);
}
- public Process createProcess(final String[] command, final Optional listener) throws IOException {
- return new ProcessBuilder().redirectErrorStream(listener.isPresent()).directory(workDir.toFile())
- .command(command).start();
- }
+ public WatchStartResult watch(BuildEventListener listener) throws IOException {
+ final ExecutorService executorBuild = Executors
+ .newSingleThreadExecutor(r -> new Thread(r, "Esbuild build listeners notify"));
+ CountDownLatch latch = new CountDownLatch(1);
+ final WatchStartResult.WatchProcess watchProcess = getProcess(executorBuild, latch);
- private record Streamer(ExecutorService executorBuild, BooleanSupplier isAlive, InputStream processStream,
- BuildEventListener listener, Consumer onExit) implements Runnable {
-
- @Override
- public void run() {
- final AtomicBoolean hasError = new AtomicBoolean();
- final StringBuilder outputBuilder = new StringBuilder();
- consumeStream(isAlive, processStream, l -> {
- logger.fine(l);
- outputBuilder.append("\n").append(l);
- if (l.contains("build finished")) {
- logger.fine("Build finished!");
- final String output = outputBuilder.toString();
- final boolean error = hasError.getAndSet(false);
- outputBuilder.setLength(0);
- executorBuild.execute(() -> {
- if (!error) {
- listener.onBuild(new WatchBuildResult(output));
- } else {
- listener.onBuild(
- new WatchBuildResult(output, new BundleException("Error during bundling", output)));
- }
- });
- } else if (l.contains("[ERROR]")) {
- hasError.set(true);
+ try {
+ executorBuild.execute(() -> {
+ try {
+ runWatchBuild(listener, latch);
+ } catch (IOException e) {
+ if (latch.getCount() == 1) {
+ latch.countDown();
+ }
}
});
- if (!hasError.get()) {
- onExit.accept(new WatchBuildResult(outputBuilder.toString()));
- } else {
- onExit.accept(new WatchBuildResult(outputBuilder.toString(),
- new BundleException("Process exited with error", outputBuilder.toString())));
- }
+ latch.await();
+
+ return new WatchStartResult(new WatchBuildResult(""), watchProcess);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ watchProcess.close();
+ throw new RuntimeException(e);
}
}
- private static String readStream(InputStream stream) {
- final StringBuilder s = new StringBuilder();
- consumeStream(() -> true, stream, l -> s.append(l).append("\n"));
- return s.toString();
- }
+ private static WatchStartResult.WatchProcess getProcess(ExecutorService executorBuild, CountDownLatch latch) {
+ final AtomicBoolean alive = new AtomicBoolean(true);
+ return new WatchStartResult.WatchProcess() {
+ @Override
+ public boolean isAlive() {
+ return alive.get();
+ }
- private static void consumeStream(BooleanSupplier stayAlive, InputStream stream, Consumer newLineConsumer) {
- try (
- final InputStreamReader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
- final BufferedReader reader = new BufferedReader(in)) {
- String line;
- while ((line = reader.readLine()) != null) {
- newLineConsumer.accept(line);
- if (!stayAlive.getAsBoolean()) {
- break;
+ @Override
+ public void close() throws IOException {
+ alive.set(false);
+ executorBuild.shutdownNow();
+ if (latch.getCount() == 1) {
+ latch.countDown();
}
}
- } catch (IOException e) {
- // ignore
- }
+ };
}
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/Main.java b/core/src/main/java/io/mvnpm/esbuild/Main.java
index 78161dc3..18105536 100644
--- a/core/src/main/java/io/mvnpm/esbuild/Main.java
+++ b/core/src/main/java/io/mvnpm/esbuild/Main.java
@@ -2,13 +2,11 @@
import java.io.IOException;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
-import io.mvnpm.esbuild.model.ExecuteResult;
import io.mvnpm.esbuild.resolve.Resolver;
public class Main {
@@ -25,9 +23,9 @@ public static void main(String[] args) throws IOException {
esbuildVersion = unParsedEsbuildVersion.split("=")[1];
}
final Path esBuildExec = Resolver.create().resolve(esbuildVersion);
- final ExecuteResult executeResult = new Execute(Paths.get(workingDirectory), esBuildExec.toFile(),
- arguments.toArray(new String[] {}))
- .executeAndWait();
- System.out.println(executeResult.output());
+ // final ExecuteResult executeResult = new Execute(Paths.get(workingDirectory), esBuildExec.toFile(),
+ // arguments.toArray(new String[] {}))
+ // .executeAndWait();
+ // System.out.println(executeResult.output());
}
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/install/BuildDependency.java b/core/src/main/java/io/mvnpm/esbuild/install/BuildDependency.java
new file mode 100644
index 00000000..f9eac4c0
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/install/BuildDependency.java
@@ -0,0 +1,87 @@
+package io.mvnpm.esbuild.install;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import io.mvnpm.esbuild.Bundler;
+import io.mvnpm.esbuild.model.WebDependency;
+
+public record BuildDependency(String name, String fileName) {
+
+ public static List getDependencies() {
+ return getWebDependencies(resolveBuildDependencies());
+ }
+
+ private static List resolveBuildDependencies() {
+ Properties dependencies = resolveDependencies();
+ List result = new ArrayList<>(dependencies.size());
+
+ dependencies.forEach((key, value) -> {
+ String name = key.toString().replaceAll("\\.version", "/%s".formatted(value));
+ String fileName = name.replace("/", "-") + ".jar";
+ result.add(new BuildDependency(name, fileName));
+ });
+
+ result.add(getEsbuildPlatformDependency(dependencies.getProperty("esbuild.version")));
+ return result;
+ }
+
+ private static Properties resolveDependencies() {
+ Properties properties = new Properties();
+ try {
+ final InputStream resource = Bundler.class.getResourceAsStream("/esbuild-java-version.properties");
+ if (resource != null) {
+ properties.load(resource);
+ }
+ } catch (IOException e) {
+ // ignore we use the default
+ }
+ return properties;
+ }
+
+ private static List getWebDependencies(List dependency) {
+ return dependency.stream()
+ .map(buildDependency -> Path.of(System.getProperty("user.home"), ".m2/repository/org/mvnpm/",
+ buildDependency.name(), buildDependency.fileName()))
+ .map(d -> WebDependency.of("org.mvnpm:" + d.getFileName().toString().replace(".jar", ""), d,
+ WebDependency.WebDependencyType.MVNPM))
+ .toList();
+ }
+
+ private static BuildDependency getEsbuildPlatformDependency(String version) {
+ String classifier = determineClassifier();
+ return new BuildDependency(String.format("at/esbuild/%s/%s", classifier, version),
+ String.format("%s-%s.jar", classifier, version));
+ }
+
+ private static String determineClassifier() {
+ final String osName = System.getProperty("os.name").toLowerCase();
+ final String osArch = System.getProperty("os.arch").toLowerCase();
+ String classifier;
+
+ if (osName.contains("mac")) {
+ if (osArch.equals("aarch64") || osArch.contains("arm")) {
+ classifier = "darwin-arm64";
+ } else {
+ classifier = "darwin-x64";
+ }
+ } else if (osName.contains("win")) {
+ classifier = osArch.contains("64") ? "win32-x64" : "win32-ia32";
+ } else {
+ if (osArch.equals("aarch64") || osArch.equals("arm64")) {
+ classifier = "linux-arm64";
+ } else if (osArch.contains("arm")) {
+ classifier = "linux-arm";
+ } else if (osArch.contains("64")) {
+ classifier = "linux-x64";
+ } else {
+ classifier = "linux-ia32";
+ }
+ }
+ return classifier;
+ }
+}
diff --git a/core/src/main/java/io/mvnpm/esbuild/install/WebDepsInstaller.java b/core/src/main/java/io/mvnpm/esbuild/install/WebDepsInstaller.java
index 00b93850..3d93142d 100644
--- a/core/src/main/java/io/mvnpm/esbuild/install/WebDepsInstaller.java
+++ b/core/src/main/java/io/mvnpm/esbuild/install/WebDepsInstaller.java
@@ -15,7 +15,6 @@
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.stream.Collectors;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -93,17 +92,6 @@ public static boolean install(Path nodeModulesDir, List dependenc
}
}
PathUtils.deleteRecursive(tmp);
- Set installedDirs = installed.stream().flatMap(i -> i.dirs().stream()).collect(Collectors.toSet());
- Set legacyDirs = mvnpmInfo.installed().stream().flatMap(i -> i.dirs().stream())
- .collect(Collectors.toSet());
- // we are not deleting all the legacy dependencies, some of the dirs might still be used by new ones (e.g version or classifier change).
- for (String legacyDir : legacyDirs) {
- if (!installedDirs.contains(legacyDir)) {
- changed = true;
- logger.log(Level.FINE, "removing package as it is not needed anymore ''{0}''", legacyDir);
- PathUtils.deleteRecursive(nodeModulesDir.resolve(legacyDir));
- }
- }
final MvnpmInfo newMvnpmInfo = new MvnpmInfo(installed);
WebDepsInstaller.writeMvnpmInfo(mvnpmInfoFile, newMvnpmInfo);
return changed;
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java
index f0afcdaf..853c24e5 100644
--- a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java
+++ b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfig.java
@@ -7,10 +7,15 @@
import java.util.Map;
import java.util.stream.Collectors;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
public record EsBuildConfig(
String esBuildVersion,
boolean bundle,
- String[] entryPoint,
+ String[] entryPoints,
boolean minify,
boolean version,
@@ -97,7 +102,7 @@ public EsBuildConfigBuilder edit() {
return new EsBuildConfigBuilder()
.esbuildVersion(this.esBuildVersion)
.bundle(this.bundle)
- .entryPoint(this.entryPoint)
+ .entryPoint(this.entryPoints)
.minify(this.minify)
.version(this.version)
.loader(this.loader)
@@ -176,7 +181,7 @@ public String[] toParams() {
((List>) value).forEach(e -> result.add("--%s:%s".formatted(convertField(fieldName), e.toString())));
} else if (value instanceof Map) {
result.addAll(mapToString(fieldName, (Map, ?>) value));
- } else if ("entryPoint".equals(field.getName())) {
+ } else if ("entryPoints".equals(field.getName())) {
result.addAll(List.of((String[]) value));
} else if (!(value instanceof Boolean)) {
String fn = convertField(fieldName);
@@ -195,6 +200,54 @@ public String[] toParams() {
return result.toArray(String[]::new);
}
+ public String toJson() {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode node = mapper.createObjectNode();
+ final Field[] fields = EsBuildConfig.class.getDeclaredFields();
+ for (Field field : fields) {
+ try {
+ final Object value = field.get(this);
+ final String fieldName = field.getName();
+
+ if ("serve".equals(fieldName)) {
+ continue;
+ }
+ if (value instanceof Boolean) {
+ node.put(fieldName, (Boolean) value);
+ } else if (value instanceof Map, ?> map) {
+ if (map.isEmpty())
+ continue;
+
+ ObjectNode subNode = mapper.createObjectNode();
+ map.forEach((key, v) -> subNode.put(key.toString(), v.toString().toLowerCase()));
+ node.set(fieldName, subNode);
+ } else if (value instanceof List> list) {
+ if (list.isEmpty())
+ continue;
+ ArrayNode arrayNode = mapper.createArrayNode();
+ list.forEach(v -> arrayNode.add(v.toString()));
+ node.set(fieldName, arrayNode);
+ } else if (value instanceof String[] list) {
+ if (list.length == 0)
+ continue;
+ ArrayNode arrayNode = mapper.createArrayNode();
+ Arrays.stream(list).toList().forEach(arrayNode::add);
+ node.set(fieldName, arrayNode);
+ } else if (value != null) {
+ node.put(fieldName, value.toString().toLowerCase());
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ try {
+ return mapper.writeValueAsString(node);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private static String convertField(String field) {
final String[] split = field.split("(?=\\p{Upper})");
return Arrays.stream(split).map(String::toLowerCase).collect(Collectors.joining("-"));
diff --git a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java
index d04795d2..8055ed72 100644
--- a/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java
+++ b/core/src/main/java/io/mvnpm/esbuild/model/EsBuildConfigBuilder.java
@@ -58,7 +58,7 @@ public class EsBuildConfigBuilder {
List external = new ArrayList<>();
- EsBuildConfigBuilder() {
+ public EsBuildConfigBuilder() {
}
public EsBuildConfigBuilder withDefault() {
diff --git a/core/src/main/java/io/mvnpm/esbuild/util/Archives.java b/core/src/main/java/io/mvnpm/esbuild/util/Archives.java
index a4c6c762..ef57f89c 100644
--- a/core/src/main/java/io/mvnpm/esbuild/util/Archives.java
+++ b/core/src/main/java/io/mvnpm/esbuild/util/Archives.java
@@ -6,6 +6,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -52,6 +54,11 @@ private static void extractEntry(Path target, String name, boolean isDirectory,
}
Files.copy(is, newPath, StandardCopyOption.REPLACE_EXISTING);
+ if (newPath.toString().contains("/bin/")) {
+ Set permissions = Files.getPosixFilePermissions(newPath);
+ permissions.add(PosixFilePermission.OWNER_EXECUTE);
+ Files.setPosixFilePermissions(newPath, permissions);
+ }
}
}
diff --git a/core/src/main/java/io/mvnpm/esbuild/util/EntryCreator.java b/core/src/main/java/io/mvnpm/esbuild/util/EntryCreator.java
new file mode 100644
index 00000000..353843de
--- /dev/null
+++ b/core/src/main/java/io/mvnpm/esbuild/util/EntryCreator.java
@@ -0,0 +1,31 @@
+package io.mvnpm.esbuild.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Scanner;
+
+import io.mvnpm.esbuild.model.EsBuildConfig;
+
+public class EntryCreator {
+ private static final String PLACEHOLDER = "<% config %>";
+
+ public static File createEntryJs(Path root, EsBuildConfig config) throws IOException {
+ Path entryFile = root.resolve("index.js");
+ try (InputStream resource = EntryCreator.class.getResourceAsStream("/template.js")) {
+ if (resource == null) {
+ throw new IOException("template not found in classpath");
+ }
+ try (Scanner scanner = new Scanner(resource, StandardCharsets.UTF_8)) {
+ String templateContent = scanner.useDelimiter("\\A").hasNext() ? scanner.next() : "";
+ String entryJs = templateContent.replace(PLACEHOLDER, config.toJson());
+ Files.writeString(entryFile, entryJs);
+ }
+ }
+
+ return entryFile.toFile();
+ }
+}
diff --git a/core/src/main/resources-filtered/esbuild-java-version.properties b/core/src/main/resources-filtered/esbuild-java-version.properties
index 1254bac2..69ceb451 100644
--- a/core/src/main/resources-filtered/esbuild-java-version.properties
+++ b/core/src/main/resources-filtered/esbuild-java-version.properties
@@ -1 +1,6 @@
-esbuild.version=${esbuild.version}
\ No newline at end of file
+esbuild.version=${esbuild.version}
+
+sass.version=${sass.version}
+immutable.version=${immutable.version}
+esbuild-sass-plugin.version=${esbuild-sass-plugin.version}
+safe-identifier.version=${safe-identifier.version}
\ No newline at end of file
diff --git a/core/src/main/resources/template.js b/core/src/main/resources/template.js
new file mode 100644
index 00000000..ba078a48
--- /dev/null
+++ b/core/src/main/resources/template.js
@@ -0,0 +1,36 @@
+const esbuild = require("esbuild");
+const plugin = require("esbuild-sass-plugin");
+
+const { version, watch, ...config } = (
+ <% config %>
+);
+
+if (version) {
+ console.log("${esbuild.version}");
+}
+
+if (watch) {
+ esbuild.context({
+ ...config,
+ plugins: [
+ plugin.sassPlugin(),
+ {
+ name: 'build-notifier',
+ setup(build) {
+ build.onEnd((result) => {
+ if (result.errors.length > 0) {
+ buildEventHandler.onBuildError("Build failed", result.errors[0].text);
+ } else {
+ buildEventHandler.onBuildComplete("Build completed");
+ }
+ });
+ }
+ }
+ ]
+ }).then(ctx => ctx.watch());
+} else {
+ esbuild.build({
+ ...config,
+ plugins: [plugin.sassPlugin()]
+ }).then(() => console.log("build finished"));
+}
\ No newline at end of file
diff --git a/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java b/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java
index 511b3c96..e0fce5d0 100644
--- a/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java
+++ b/core/src/test/java/io/mvnpm/esbuild/ExecuteTest.java
@@ -3,27 +3,23 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import org.junit.jupiter.api.Test;
-import io.mvnpm.esbuild.model.EsBuildConfig;
import io.mvnpm.esbuild.model.EsBuildConfigBuilder;
import io.mvnpm.esbuild.model.ExecuteResult;
-import io.mvnpm.esbuild.resolve.Resolver;
public class ExecuteTest {
@Test
public void shouldExecuteEsBuild() throws IOException {
- final EsBuildConfigBuilder esBuildConfig = EsBuildConfig.builder();
- esBuildConfig.version(true);
- final String defaultVersion = Bundler.ESBUILD_EMBEDDED_VERSION;
- final Path path = Resolver.create().resolve(defaultVersion);
- String workingDirectory = System.getProperty("user.dir");
- final ExecuteResult executeResult = new Execute(Paths.get(workingDirectory), path.toFile(), esBuildConfig.build())
+ final EsBuildConfigBuilder esBuildConfig = new EsBuildConfigBuilder();
+ esBuildConfig.version();
+ Path workingDirectory = Files.createTempDirectory("testBuild");
+ final ExecuteResult executeResult = new Execute(workingDirectory, esBuildConfig.build())
.executeAndWait();
- assertEquals(defaultVersion + "\n", executeResult.output());
+ assertEquals("", executeResult.output());
}
}
diff --git a/core/src/test/java/io/mvnpm/esbuild/util/EntryCreatorTest.java b/core/src/test/java/io/mvnpm/esbuild/util/EntryCreatorTest.java
new file mode 100644
index 00000000..b41b93ed
--- /dev/null
+++ b/core/src/test/java/io/mvnpm/esbuild/util/EntryCreatorTest.java
@@ -0,0 +1,30 @@
+package io.mvnpm.esbuild.util;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+import io.mvnpm.esbuild.model.EsBuildConfig;
+
+public class EntryCreatorTest {
+
+ @Test
+ void createEntryJs() throws URISyntaxException, IOException {
+ // given
+ Path test = Files.createTempDirectory("createEntryJsTest");
+ EsBuildConfig esBuildConfig = EsBuildConfig.builder().entryPoint(new String[] { "app.js" })
+ .outDir(test.resolve("dist").toString()).format(EsBuildConfig.Format.ESM).build();
+
+ // when
+ EntryCreator.createEntryJs(test, esBuildConfig);
+
+ // then
+ Path output = test.resolve("index.js");
+ assertTrue(Files.exists(output));
+ }
+}