Preloaded JavaScript

Overview

The ScriptCompiler and ScriptProvider APIs are designed to optimize the performance of your game’s UI by pre-compiling JavaScript files, significantly reducing the runtime overhead associated with initial JavaScript loading and enabling faster UI load times.

  • The FCohtmlScriptCompiler class performs the reading/compilation of your JavaScript files - it takes a file path and transforms it into a ready-to-use bundle of raw and compiled file data.
  • The ICohtmlScriptProvider interface is used to “pass” your data to Prysm. There is a default implementation of the interface, called FCohtmlScriptProvider (seen in the example below) which should cover most simple use-cases related to storing and modifying a cache of compiled scripts. You can also provide your custom implementation of the interface and choose what/which compiled data to pass, depending on the specific needs of your game.

How to Use

For most developers, integrating script pre-compilation can be done in a few steps, namely:

  1. Make sure that the System has been created. This can usually be done through FCohtmlSystemHolder::GetSystem(), but in some cases you might need to create the System yourself.
  2. Initialize the FCohtmlScriptCompiler object and your preferred ICohtmlScriptProvider object - this can be the default FCohtmlScriptProvider implementation or your custom one.
  3. Let Prysm know about your ScriptProvider object through the ICohtmlPlugin::OnGetScriptProvider delegate.
  4. Compile your scripts using the ScriptCompiler and add (i.e. cache) them inside your ScriptProvider. At this point the ScriptCompiler object should no longer be needed and can be destroyed.
  5. Load your HTML page - Prysm will call ICohtmlScriptProvider::GetScriptCacheEntry whenever a resource is requested. If compiled data is found/returned, it will skip the usual read/compile steps and use the compiled data instead.
  6. Dispose of the cached script memory after UI has loaded or the entire ScriptProvider object if you prefer to.

Here’s a simple example of how to pre-compile JavaScript files at startup and manage them during gameplay, using the default ScriptProvider implementation.

// The System needs to be alive for script compilation
auto System = FCohtmlSystemHolder::GetSystem();
// Initialize the ScriptCompiler
TUniquePtr<FCohtmlScriptCompiler> ScriptCompiler(new FCohtmlScriptCompiler(System));
// Initialize the provided default implementation of the ScriptProvider.
// Only used as TSharedPtr here to make it easier to capture into a lambda.
// Ideally, you should have your own lifetime management.
auto ScriptProvider = TSharedPtr<FCohtmlScriptProvider>(new FCohtmlScriptProvider);
ICohtmlPlugin::Get().OnGetScriptProvider.BindLambda([ScriptProvider]() {
	return ScriptProvider.Get();
});
// This can be a file visitor, directory watcher, etc.
auto FilesToPreload = GetFiles();
for (auto& FilePath : FilesToPreload)
{
    // Read and compile the script
    auto CompiledData = ScriptCompiler->CompileScript(FilePath);
    // Add the compiled data to the ScriptProvider cache, which will take ownership of it
    ScriptProvider->AddScriptCacheEntry(FilePath, CompiledData);
}
// Prysm will try to match scripts used by "my_page.html" with ones in your cache
GetView()->LoadURL("my_page.html");
// Clear the cache when the UI has loaded
ScriptProvider->ClearScriptCache();

Advanced Usages and Custom Flows

For developers with more complex requirements, such as compiling scripts during packaging or implementing custom caching strategies, the APIs offer extensive customization options.

Modifying and preserving the script cache between runs

You can extract, modify and “set” the script cache inside the default FCohtmlScriptProvider implementation. For example, you could compile all of your scripts during packaging, extract and save them to disk, then load and re-insert them in the cache when your game starts.

// ...
// Compile scripts and add them to your cache following the example above
// ...
auto PrecompiledScripts = ScriptProvider->ModifyCachedScripts(); // Extract the scripts from the cache.
SaveScriptsToDisk(PrecompiledScripts); // Save them to the disk or inside your game package.
// When your game starts
auto PreloadedScripts = LoadFromDisk(); // Load the scripts from disk.
ScriptProvider->SetCachedScripts(PreloadedScripts); // Insert them back in the cache.

Custom ScriptProvider Implementation

If you need to load pre-compiled scripts from disk on demand or implement your own path resolution, you can override the default ScriptProvider behavior. The only relevant method to focus on is ICohtmlScriptProvider::GetScriptCacheEntry. This method gets called whenever your UI requests to read a file from disk - here you can provide your prepared raw and compiled JavaScript data, or return nullptr and let the file be read/compiled as usual. The “default” FCohtmlScriptProvider implementation that comes with Prysm is just a cache file paths, mapped to their respective raw/compiled data. When using a custom implementation you can organize and manage your compiled files however you want - for example you might not cache them at all, but instead read them from disk or fetch them from a server, if this suits your needs better.

Here is a sample implementation of a custom ScriptProvider:

// Implement your custom ScriptProvider
class CustomScriptProvider : public ICohtmlScriptProvider
{
public:
    // Implement your custom way to match file paths to their CohtmlCompiledScriptData
    // return nullptr if and entry is not found
    virtual FCohtmlCompiledScriptDataPtr GetScriptCacheEntry(const FString& FilePath) override
    {
        return GetMyPrecompiledData(FilePath); // Load data from disk, server, etc.
    }

};
// Bind the OnGetScriptProvider delegate and pass your override to Prysm
ICohtmlPlugin::Get().OnGetScriptProvider.BindLambda([]() {
    return MyScriptProviderManager::GetCustomScriptProvider();
});

Additional info

For more in-depth info on JavaScript preloading, please refer to the following pages:

  • API Reference for the FCohtmlScriptProvider class
  • API Reference for the FCohtmlScriptCompiler class
  • The native JavaScript preloading documentation page. The FCohtmlScriptProvider and FCohtmlScriptCompiler classes serve as wrappers for the the functionality described in this page.