HTML5 Compiling Failure

Krimm

  • *
  • Posts: 113
I'm currently working on a simple new HTML5 game, which I can test build to HTML5 no problem, but when I try to publish to HTML5, I get the "Encountered errors while building your game" message. The logs are attached.

I've tried cleaning the project, but that didn't work. I can build to HTML5 in new projects, and I can build to HTML5 in older projects as well that are far more complex, so I'm not sure what I'm missing.

Edited to mention I'm on build 4.1.0 b11050

« Last Edit: September 14, 2022, 12:47:51 pm by Krimm »

Justin

  • *
  • Posts: 4663
I investigated this a couple weeks ago. Here are the notes I took at the time.

When publishing to HTML5 on Windows, during the closure compiler step, the build may error with a message like this:
Code: [Select]
[haxelib.exe] java.nio.file.InvalidPathException: Illegal char <:> at index 4: file:///C:/Users/Username/AppData/Local/Stencyl/libs/haxelib/shohei909/tweenxcore/1.0.4/tweenxcore/Tools.hx
[haxelib.exe]  at sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
[haxelib.exe]  at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
[haxelib.exe]  at sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
[haxelib.exe]  at sun.nio.fs.WindowsPath.parse(WindowsPath.java:94)
[haxelib.exe]  at sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:255)
[haxelib.exe]  at sun.nio.fs.AbstractPath.resolveSibling(AbstractPath.java:66)
[haxelib.exe]  at com.google.javascript.jscomp.SourceMapResolver.getRelativePath(SourceMapResolver.java:102)
[haxelib.exe]  at com.google.javascript.jscomp.Compiler.getSourceMapping(Compiler.java:2883)
[haxelib.exe]  at com.google.javascript.jscomp.SourceMap.addMapping(SourceMap.java:175)
[haxelib.exe]  at com.google.javascript.jscomp.CodePrinter$MappedCodePrinter.generateSourceMap(CodePrinter.java:153)
[haxelib.exe]  at com.google.javascript.jscomp.CodePrinter.toSource(CodePrinter.java:849)
[haxelib.exe]  at com.google.javascript.jscomp.CodePrinter.access$300(CodePrinter.java:40)
[haxelib.exe]  at com.google.javascript.jscomp.CodePrinter$Builder.build(CodePrinter.java:778)
[haxelib.exe]  at com.google.javascript.jscomp.Compiler.toSource(Compiler.java:2278)
[haxelib.exe]  at com.google.javascript.jscomp.Compiler.lambda$toSource$11(Compiler.java:2239)
[haxelib.exe]  at com.google.javascript.jscomp.CompilerExecutor.runInCompilerThread(CompilerExecutor.java:129)
[haxelib.exe]  at com.google.javascript.jscomp.Compiler.runInCompilerThread(Compiler.java:826)
[haxelib.exe]  at com.google.javascript.jscomp.Compiler.toSource(Compiler.java:2201)
[haxelib.exe]  at com.google.javascript.jscomp.Compiler.lambda$toSource$9(Compiler.java:2158)
[haxelib.exe]  at com.google.javascript.jscomp.CompilerExecutor$2.call(CompilerExecutor.java:102)
[haxelib.exe]  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[haxelib.exe]  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[haxelib.exe]  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[haxelib.exe]  at java.lang.Thread.run(Thread.java:748)

It would appear that there are various issues with source map support with Haxe-generated JS and the closure compiler.

First, Haxe uses url-encoding for the source map path in the generated javascript file. This is correct. Closure, on the other hand, thinks that it's a file path, and uses java.nio.file.Path to look it up relative to the js file. This causes, for example, paths with spaces in them not to work at all, since the space will be represented as %20. This can be resolved by the following patch to closure:

Code: [Select]
--- a/src/com/google/javascript/jscomp/Compiler.java
+++ b/src/com/google/javascript/jscomp/Compiler.java
@@ -3030,6 +3030,11 @@ public class Compiler extends AbstractCompiler implements ErrorHandler, SourceFi
     String resultOriginalPath = result.getOriginalFile();
     final String relativePath;

+    if(resultOriginalPath.startsWith("file:///"))
+    {
+      resultOriginalPath = resultOriginalPath.substring("file:///".length());
+    }
+
     // Resolving the paths to a source file is expensive, so check the cache first.
     if (sourceMapOriginalPath.equals(resolvedSourceMap.originalPath)
         && resultOriginalPath.equals(resolvedSourceMap.sourceMapPath)) {
@@ -3040,7 +3045,7 @@ public class Compiler extends AbstractCompiler implements ErrorHandler, SourceFi
       if (source == null && !isNullOrEmpty(resultOriginalPath)) {
         source =
             SourceMapResolver.getRelativePath(
-                sourceMap.getOriginalPath(), result.getOriginalFile());
+                sourceMap.getOriginalPath(), resultOriginalPath);
         if (source != null) {
           sourceMapOriginalSources.putIfAbsent(relativePath, source);
         }

Second, absolute paths using the file:// protocol in sourcemap sources aren't handled correctly. Closure thinks that everything either starts with a / and is an absolute path, or it's a relative file path. Again, java.nio.file.Path is used, leading to possible errors like that reported by Krimm. This can be worked around with the following patch, but it's not particularly robust.

Code: [Select]
--- a/src/com/google/javascript/jscomp/Compiler.java
+++ b/src/com/google/javascript/jscomp/Compiler.java
@@ -3030,6 +3030,11 @@ public class Compiler extends AbstractCompiler implements ErrorHandler, SourceFi
     String resultOriginalPath = result.getOriginalFile();
     final String relativePath;

+    if(resultOriginalPath.startsWith("file:///"))
+    {
+      resultOriginalPath = resultOriginalPath.substring("file:///".length());
+    }
+
     // Resolving the paths to a source file is expensive, so check the cache first.
     if (sourceMapOriginalPath.equals(resolvedSourceMap.originalPath)
         && resultOriginalPath.equals(resolvedSourceMap.sourceMapPath)) {
@@ -3040,7 +3045,7 @@ public class Compiler extends AbstractCompiler implements ErrorHandler, SourceFi
       if (source == null && !isNullOrEmpty(resultOriginalPath)) {
         source =
             SourceMapResolver.getRelativePath(
-                sourceMap.getOriginalPath(), result.getOriginalFile());
+                sourceMap.getOriginalPath(), resultOriginalPath);
         if (source != null) {
           sourceMapOriginalSources.putIfAbsent(relativePath, source);
         }

The reason I never ran into this with my test game is that my typical test game has a space in the name, so I was running into issue #1, and closure never event attempted to resolve file paths in the first place.

However, if everything was working as intended (apart from this bug), I would expect that publishing an HTML5 game would always fail, but Krimm's later reports seem to indicate that the bugs occurrence is a bit hard to predict. I feel like there must be more bugs with closure's sourcemap processing feature, and I don't think I can afford the time to look into them.

In the end, I think I'll just remove sourcemap processing from the build in order to avoid this bug in the future.
For Live Support: Join our discord server and ping me @justin.
I'm most often available between 10am and 10pm Japan time. (GMT+9)

Krimm

  • *
  • Posts: 113
Hey Justin, thanks so much for looking in to this! That makes sense, since the games that failed to build are all single word project names, but the ones that didn't fail are multiple words that contain a space in them. I ultimately managed to get around this issue by making a new project that has a space in the name, not realizing that was what fixed it.

Justin

  • *
  • Posts: 4663
Source map processing is disabled for now, as of 4.1.0-beta3/b11123, which will prevent this failure.
For Live Support: Join our discord server and ping me @justin.
I'm most often available between 10am and 10pm Japan time. (GMT+9)