Preloads

What is a preload?

A preload is a script that is loaded into a window before the actual content of that window is loaded. You might have already met preloads in Smart desktop quickstart. If you haven’t, we recommend that you check out that tutorial first.

A preload runs every time the window reloads. This way, the component behaves the same way each time, and the users can have the same experience each time they switch to the window that has the preload. You can include multiple preloads for the same window. They will be loaded in the order in which they were defined.

Sometimes the same code can be used both as a preload and as an app. We provide a sample, the Bloomberg bridge client, that can be used both ways.

Advantages

A preload provides added flexibility because it allows you to run additional code in the window without changing code for the app that the window belongs to.

Another advantage of a preload is that you can write it once and then push it to many apps without redeploying them. This code reuse saves time both in terms of coding and in terms of deployment.

Finally, there is one more advantage. You might have an app that several teams use, but each team interacts with it in different ways. In this situation, you can use preloads to customize the app interactions for each team without modifying the source code of the app.

Preloads are secure

If preloads make you nervous, it’s probably because the first thing that comes to mind is news reports about stealing credit card information or some other malicious use. While this is indeed an example of what a preload could do, there are countless legitimate examples of useful preloads that don’t intend to do harm and are safe to run.

The main problem with preloads in general occurs when there are no safeguards and anyone can run one. In the case of Finsemble, this doesn’t happen. That’s because the only people that can configure an app to run a preload are the people who control the desktop experience. Nobody else can come in and run a preload for any window on a smart desktop. So preloads in Finsemble present no added security risk. If you trust your desktop experience team, there is no reason for you to worry about the security of Finsemble preloads.

We take security seriously. For this reason, we have some restrictions on running preloads. Before you can run a preload, you need to make sure that at least one of these conditions is true:

  • The preload is trusted. To specify trust, set window.options.securityPolicy = "trusted". See Trusted preloads for more detail.

  • The component is trusted. If your component is on the same domain as Finsemble, you don’t have to do anything because all components within the same domain are automatically trusted. If it isn’t, you can set the trust explicitly by specifying Window.webPreferences.preload = true. More about trusted policies.

Important Important: If neither of these conditions is met, Finsemble won’t apply your preload.

A preload isn’t always the answer

In principle, anything can be a preload. You could even manage your entire ecosystem this way, but we definitely don’t recommend it. Powerful as preloads are, you don’t want to overuse them. For example, there is no need for a preload if you have access to the source code that you can easily update. It makes more sense to modify that source code to behave exactly as you want instead of adding one more layer of complexity to your environment. Customizing your app directly is a cleaner approach to managing your ecosystem. It is a good practice to keep the code for an app in one place to avoid the code for the app and the code for the associated preload to diverge in undesirable ways.

On the other hand, when you update an app, you need to then redeploy it. If you don’t want to or can’t redeploy, you can use a preload instead. So deciding whether you want to use a preload or not is also about what’s easier. If redeploying is hard or disruptive, use preloads. But do so with the understanding that it’s a more complex solution than customizing directly.

You also need to consider how your enterprise is organized. Many companies divide responsibilities between the desktop team, which owns how apps talk to each other, and the dev team, which owns what the apps actually do. Because of this division of responsibility, a desktop team might choose to use a preload so that they can control the app interaction without involving the dev team. Alternatively, the dev team might decide to modify the app instead of using a preload. Usually, organizations figure out the approach that is the easier overall.

Examples of preloads

As we have seen, preloads are versatile and you can use it for many different tasks. You can add a preload that handles an event such as a button click or javascript event. For example, a Web app component could listen for content and navigate to a new url. The preload listens to messages and then navigates to or displays content you want.

Another example is to customize an external app, such as a financial page like the Web app Yahoo Finance. You can use a preload script to add the ability to listen for context. Your preload then could listen for stock symbols and navigate to information about that specific symbol.

One common usage is to override a built-in API. For example, you can use native overwrites in source preloads. nativeoverrides.js customizes window.open, which opens a component, and window.alert so that you can change the dialog box to a Finsemble message. This is one way to adapt a web app to work with Finsemble.

Some Finsemble customers add a layer between their code and Finsemble itself. This way, they expose their API to insulate from changes to Finsemble. Your own API makes calls to other APIs, and you can use preloads for that.

Finsemble seed contains some example preloads:

  • nativeOverrides.js - demonstrates how to override native functions, using window.open as an example. In this preload, instead of opening a new window, we redirect that function to call LauncherClient.spawn. We also overwrite the alert method to send a notification through Finsemble instead.
  • registration.js - processes a user registration and prevents the user from registering multiple times.
  • zoom.js - allows the user to control hotkeys and zoom levels.

Here is another useful example: you can use a preload to help make your web app FDC3-compliant without changing the code for the app itself:

	const { log, error } = FSBL.Clients.Logger;

	log("Initializing context and intent listeners");

	const contextHandler = (context) => {
		const { ticker = null } = context.id;
		if (ticker) {
			log("Received context: ", context);
			window.location.href = `https://finance.yahoo.com/chart/${ticker}`;
		} else {
			error("context does not have a ticker key");
		}
	};

	fdc3.addIntentListener("ViewChart", contextHandler);
	fdc3.addContextListener("fdc3.instrument", contextHandler);
}

//standard finsemble initialize pattern
if (window.FSBL && FSBL.addEventListener) {
	FSBL.addEventListener("onReady", main);
} else {
	window.addEventListener("FSBLReady", main);
}

We provide this example preload and complete instructions about how to use it in finsemble-fdc3.

To add the FDC3 preload to your component, set component.preload in its configuration to the path to the built preload script, e.g. "$applicationRoot/preloads/FDC3Client.js". Alternatively, if you have multiple preload scripts, add this one to an array of their paths.

Add a section to your component config, foreign.services.fdc3, to specify intents and associated context types that your component can handle:

{
    "FDC3 Component": {
        "window": {},
        "component": 
        {   "preload": [
            "$applicationRoot/preloads/FDC3Client.js"
                       ]
        },
        "foreign": {
            "services": { 
                "fdc3": {
                    "intents": [
                        {
                            "name": "StartCall",
                            "displayName": "Call",
                            "contexts": [ 
                                "fdc3.contact"
                            ] 
                        } 
                    ] 
                } 
            },  
            "components": {
                "Toolbar": {
                    "iconURL": "$applicationRoot/assets/img/Finsemble_Taskbar_Icon.png"    
                }
            } 
        }
    }
}

In addition to adding the preload, there are more steps you need to take. See the full sample for details.

How to add a preload

After you write your preload, you need to tell Finsemble to apply it. To do so, you need to add it to the config file. Keep in mind that the order in which you specify the preloads matters. The preloads are loaded in the same order in which they appear in the config file.

There are several ways to add preloads:

  • Single component - a preload applies only to the specific component
  • Multiple components - a preload is applied to several components
  • Launchable - applied only to components that can be launched
  • All components - a preload is applied to every component, including built-in components (global preload). These preloads can be very powerful.

Important Important: For security reasons, global preloads are applied to trusted components only, unless the preload itself is set up as trusted.

What to watch out for

Preloads are powerful and provide flexibility, but there are some issues you need to be aware of: race conditions and caching. Let’s take a look at these.

Race conditions

Preloads run early, which means they can run before the javascript console is set up or before your component is loaded and elements are created. In some cases that’s fine. But in other cases, a preload needs some other object to be loaded before it can complete its tasks.

If your preload needs an element that doesn’t exist yet, this creates a problem that is often difficult to debug due to inconsistent results. Sometimes things will work as expected, and at other times they don’t. This is difficult to debug because when it works you might think everything is fine when in fact it isn’t. You just had a lucky run. This issue is due to race conditions. In other words, sometimes the component would be created before it’s needed, and at other times it wouldn’t be there yet.

To remedy this issue, you need to synchronize actions your preload performs with the window. If you need some item to be loaded before your preload, you can use events to make sure things are ready. In our example, we use addEventListener with the FSBLReady event as the first parameter:

if (window.FSBL && FSBL.addEventListener) {
    FSBL.addEventListener("onReady", init);}
else {
    window.addEventListener("FSBLReady", init);
}

Caching

Finsemble caches preloads to increase efficiency. Caching works well as long as there are no changes to the preload. But while you’re debugging or updating your preload and trying to test its behavior, you need to be aware that the old version might still be cached. If it is, that old version will be used instead of the new one that you want to test. To verify that you’re using the correct version of your preload, make sure the server gives the appropriate cache headers.

If you’re still having trouble seeing changes in the preloads and suspect that it’s because of caching, you might want to restart Finsemble.

See also

Integrating HTML applications
Lifecycle events