Is it possible to include HTML5 JS files from the project or plugin?

I plan on creating an HTML5 plugin that injects utility.js so that some of my HTML5 code is blueprintable. I’ll provide some custorm JS and some custom Blueprint classes. The BP implementation will call the HTML5 code with callbacks that will invoke BP delegates.

The current HTML5 JS build process combines JS templates in the build process using only the JS templates from the editor installation folder.

https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.Automation.cs#L146

	// Gather utlity .js files and combine into one file
	string[] UtilityJavaScriptFiles = Directory.GetFiles(JSDir, "*.js");

	string DestinationFile = OutDir + "/Utility.js";
	File.Delete(DestinationFile);
	foreach( var UtilityFile in UtilityJavaScriptFiles)
	{
		string Data = File.ReadAllText(UtilityFile);
		File.AppendAllText(DestinationFile, Data);
	}

This process should be changed to also pick up any JS files from the project and from the plugins.

Any JS files that are found in ProjectName\Build\HTML5 should be picked up.

Also any JS files that are found in ProjectName\Plugins\PluginName\Build\HTML5 should be picked up.

That will allow projects and plugins to provide JS to be included in the build.

In the meantime, projects and plugins have to manually copy custom JS here:

C:\Program Files (x86)\Epic Games\4.14\Engine\Build\HTML5

This should make including JS script easier than copying custom scripts to the program files.

I created a Pull Request to add this feature.

Add support for including project and plugin JS

https://github.com/EpicGames/UnrealEngine/pull/3251

https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Programs/AutomationTool/HTML5/HTML5Platform.Automation.cs#L146

Added code:

		// Gather utlity .js files and combine into one file
		string[] UtilityJavaScriptFiles = Directory.GetFiles(JSDir, "*.js");

		string DestinationFile = OutDir + "/Utility.js";
		File.Delete(DestinationFile);
		foreach( var UtilityFile in UtilityJavaScriptFiles)
		{
			string Data = File.ReadAllText(UtilityFile);
			File.AppendAllText(DestinationFile, Data);
		}

		// Gather utlity .js files from project and combine into one file
		string ProjectJSDir = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Build", "HTML5");
		if (Directory.Exists(ProjectJSDir))
		{
			UtilityJavaScriptFiles = Directory.GetFiles(ProjectJSDir, "*.js");
			foreach (var UtilityFile in UtilityJavaScriptFiles)
			{
				string Data = File.ReadAllText(UtilityFile);
				File.AppendAllText(DestinationFile, Data);
			}
		}

		// Gather utlity .js files from plugins and combine into one file
		string ProjectPluginsDir = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Plugins");
		if (Directory.Exists(ProjectPluginsDir))
		{
			foreach (var PluginName in Directory.GetDirectories(ProjectPluginsDir))
			{
				string PluginJSDir = Path.Combine(PluginName, "Build", "HTML5");
				if (!Directory.Exists(PluginJSDir))
				{
					continue;
				}
				UtilityJavaScriptFiles = Directory.GetFiles(PluginJSDir, "*.js");
				foreach (var UtilityFile in UtilityJavaScriptFiles)
				{
					string Data = File.ReadAllText(UtilityFile);
					File.AppendAllText(DestinationFile, Data);
				}
			}
		}

replied at: https://github.com/EpicGames/UnrealEngine/pull/3251#issuecomment-280066700

to close this thread:
what you’re looking for already exists within the Engine architecture. please take a look at:

you can use that as starting basis for your plugin.

It looks like the existing build script can include JS files.

https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/HTML5/HTML5JS/HTML5JS.Build.cs

Sample JS:
https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/HTML5/HTML5JS/Private/HTML5JavaScriptFx.js

The C++ hooks:
https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/HTML5/HTML5JS/Public/HTML5JavaScriptFx.h

All of the links to github on this page are 404. Can anyone update the answer?

When I try to add my own js files to the build by editing the project.build.cs like this:

if (Target.Platform == UnrealTargetPlatform.HTML5)
{
    PublicAdditionalLibraries.Add("JSEvents.js");
}

It tells me that the file doesn’t exist, which is obviously because it searches for it in the Epic Games\UE_4.22\Engine\Source\ and not in the project folder…

Any ideas?

You need to link your Epic account with your Github Account in order to see the links.

I did so, but it didn’t help.

Follow these steps.

OK, it works now. Thanks.

But it is still not clear how can I add my own JS function from outside of HTML5JavaScriptFx.js.

Now, I was able to add my own JS file to the build. But I just can’t figure out how to define a handler like this one:

UE_RegisterCustomListener: function(listener) {
UE_JSlib.UE_CustomEvent = function() {
Runtime.dynCall(‘v’, listener);
}
},

unless I put it directly in the HTML5JavaScriptFx.js, which does work. But I need to modify the engine files on all of the machines I want to use for building… Obviously it would be much nicer if I could define the function in one of my project files.

Any ideas?

Does this mean you should not use emscripten but instead JS directly to setup communication between HTML and UE4?.
Can you explain more as i don’t really understand this. What i’m looking for is ways to communicate with blueprints i create in UE4 and then package to HTML5 and then call with html/js/react in the browser.
I’ve used VaRest to communicate between bp and html ,but when packaging UE4 to HTML5 i get an error in the browser when loading webgl, which i guess is because of the plugin VaRest. So i’m now trying to find a more stable way to setup communcation in the browser.

I caught up to you.

The example listed works for a plugin inside the engine. But how do you make it work for a 3rd party plugin so that it can search to find your file.

I’m trying this.

public class UE4_Speech : ModuleRules
{
	public UE4_Speech(ReadOnlyTargetRules Target) : base(Target)
	{
        if (Target.Platform == UnrealTargetPlatform.HTML5)
        {
            PublicAdditionalLibraries.Add("Plugins/UE4_Speech/Source/UE4_Speech/Private/WebGLSpeechDetectionPlugin.js");
            PublicAdditionalLibraries.Add("Plugins/UE4_Speech/Source/UE4_Speech/Private/WebGLSpeechSynthesisPlugin.js");
        }

The error I get is.

Output: // The Module object: Our interface to the outside world. We import
PackagingResults: Error: ENOENT: no such file or directory, open ‘C:\Program Files\Epic Games\UE_4.21\Engine\Source\Plugins\UE4_Speech\Source\UE4_Speech\Private\WebGLSpeechDetectionPlugin.js’" | Error: ENOENT: no such file or directory, open ‘C:\Program Files\Epic Games\UE_4.21\Engine\Source\Plugins\UE4_Speech\Source\UE4_Speech\Private\WebGLSpeechDetectionPlugin.js’

Like you said it’s looking in program files and not in the project folder.

I could put together an absolute path in C#, but that doesn’t seem like the best way to go.

There’s also a uproject setting that says a plugin has content. I’ll try that option…

This compiled for HTML5. I used ModuleDirectory to get the full path to the JS to include. I don’t actually see the file copied in the build HTML5 folder though…

// Some copyright should be here...

using UnrealBuildTool;

public class UE4_Speech : ModuleRules
{
	public UE4_Speech(ReadOnlyTargetRules Target) : base(Target)
	{
        if (Target.Platform == UnrealTargetPlatform.HTML5)
        {
            string path = System.IO.Path.Combine(ModuleDirectory, "Private/WebGLSpeechDetectionPlugin.js").Replace("\\", "/");
            System.Console.WriteLine("Include {0}", path);
            PublicAdditionalLibraries.Add(path);

            path = System.IO.Path.Combine(ModuleDirectory, "Private/WebGLSpeechSynthesisPlugin.js").Replace("\\", "/");
            System.Console.WriteLine("Include {0}", path);
            PublicAdditionalLibraries.Add(path);
        }

Logging shows the correct full path.

Include C:/Private/UE4_SpeechDemo/Plugins/UE4_Speech/Source/UE4_Speech/Private/WebGLSpeechDetectionPlugin.js

Include C:/Private/UE4_SpeechDemo/Plugins/UE4_Speech/Source/UE4_Speech/Private/WebGLSpeechSynthesisPlugin.js

To make it work, did you include the plugin in a source build of the engine? It doesn’t seem to include the JS files as a project plugin.

think of emscripten is a “compiler” – this translates the C++ code to (what we now use) WebAssembly (think of this as binary efficient javascript for the web browser).

that said, let’s try a demo. to use the files in the attached zip:

  • create a C++ First Person template, and NAME it: CPP_FP

  • unzip the attached zipfile and drop it in Source/.

  • package for HTML5

  • open a command prompt to your packaged output

  • run HTML5LaunchHelper.exe or python -m SimpleHTTPServer 8000 (again, from the where the packaged files are created)

  • open your browser to http://localhost:8000

  • open the developer tools via: Control+Shift+I (as in “eye”)

  • click on the Console tab in the developer tools window

  • back in the browser, click on CPP_FP.html

  • wait for the game to finish loading up

  • in the console tab – you should see foo printed in there, this will correspond to the C++ to JS call you will see at the end of ACPP_FPCharacter::BeginPlay() in CPP_FPCharacter.cpp

  • in the console tab, type the following:

  • MyProject_JSLibs.call_HTML5_to_UE4_function()

  • after pressing enter (which will demonstrate a JS to C++ call) – in the game (browser), you should see the character shoot a single round

i hope this is a clear example of your question.

you can diff the files before copying the zipped files to see what edits were needed to make this all work.

I looked over your sample files. It’s a similar setup to the HTML sample.

Are there any restrictions? For this to work does it have to be in Source/ folder or can it also work in Plugins/ folder?

yes, this concept will work for Plugins.

for restrictions, take a look at: Engine/Plugins/Experimental/HTML5Networking/

  • HTML5Networking.uplugin
  • Source/HTML5Networking/HTML5Networking.Build.cs

there, you will see an example of including a plugin that’s used in HTML5:

  • in uplugin, you will see HTML5 whitelisted in the platforms list (this trips up a lot of developers when it comes to enabling the plugin for either favorite plugins – sometimes, just sticking in your platform of choice might work out of the box)
  • and, in the Build.cs file, you can add the PublicAdditionalLibraries.Add(jsFilePath); line to include your custom JS file when the plugin is enabled

hope this helps!

I would gladly answer this, but I don’t understand the question…

I use this code to add my custom JS file to the build:

if (Target.Platform == UnrealTargetPlatform.HTML5) 
{            
    string dir = Path.GetDirectoryName(Target.ProjectFile.ToString());
    Console.WriteLine("Build.cs::HTML5: " + dir + "\n");
            
    PublicAdditionalLibraries.Add(dir + "/Source/MyProject/JSEvents.js");            
}

I made a sample repro project in 4.22. Here’s a sample project that includes SampleHTML5.js, but it’s not actually copying the file or the content to the HTML5 build folder even though I’ve whitelisted the platform. Shouldn’t this work?

Here’s a simple UE 4.22 project for testing JS:

What content?

Anyway it is not supposed to copy that js file to the output folder. It’s a way to tell emscripten how to link your js and C++…

I would expect that with this header:

If I invoke UE_InitSampleHTML5 it would invoke the JavaScript and log a message…

Should the file content of SampleHTML5.js get copied into the build? Or is this a manual step? Or is the JS converted to C++ and put into the binary data?

I’ve noticed nothing can be found when I search for UE_InitSampleHTML5 in the build folder…