Skip to content

Commit

Permalink
fix: fixed how the web chat script is loaded to avoid duplicates (#19)
Browse files Browse the repository at this point in the history
[skip ci]
  • Loading branch information
TazmanianDI authored May 23, 2023
1 parent 4c10a9d commit 4220724
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 49 deletions.
47 changes: 17 additions & 30 deletions src/WebChatContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@ const DEFAULT_BASE_URL = 'https://web-chat.global.assistant.watson.appdomain.clo
// Indicate if debugging is enabled.
let debug = false;

// The first time the container is mounted, we need to load the javascript for web chat from the CDN. This should
// only happen once. This Promise is used to ensure that and to allow anyone to wait for that script to be loaded.
let loadWebChatScriptPromise: Promise<unknown>;

// The URL that was used to load the web chat javascript. This is to ensure we don't attempt to load different scripts.
let loadedWebChatURL: string;

interface ManagedWebChat {
/**
* The config for the web chat that is loaded.
Expand Down Expand Up @@ -256,34 +249,28 @@ async function ensureWebChatScript(webChatConfig: WebChatConfig, hostURL: string
webChatConfig.clientVersion || 'latest'
}/WatsonAssistantChatEntry.js`;

const loadedWebChatURL = (window as any).wacWebChatContainerScriptURL;
if (loadedWebChatURL && loadedWebChatURL !== scriptURL) {
const message =
'Web chat has already been loaded using a different URL. This component does not support loading web chat' +
' using multiple URLs including different versions of web chat.';
const message = `Web chat has already been loaded using a different URL (${loadedWebChatURL}). This component does not support loading web chat using multiple URLs including different versions of web chat. The current code attempted to load from ${scriptURL}.`;
logger(null, message);
}
loadedWebChatURL = scriptURL;

if (!loadWebChatScriptPromise) {
loadWebChatScriptPromise = loadWebChatScript(scriptURL);
// Check to see if we already have a Promise for loading this script. We're using a window property to cover the
// case where multiple library instances are being used that can't necessarily share module state.
if (!(window as any).wacWebChatContainerScriptPromise) {
logger(null, `Loading the web chat javascript from ${scriptURL}.`);

(window as any).wacWebChatContainerScriptPromise = new Promise<void>((resolve, reject) => {
const scriptElement = document.createElement('script');
scriptElement.onload = () => resolve();
scriptElement.onerror = () => reject();
scriptElement.src = scriptURL;
document.head.appendChild(scriptElement);
(window as any).wacWebChatContainerScriptURL = scriptURL;
});
}
await loadWebChatScriptPromise;
}

/**
* Loads the web chat javascript from the CDN.
*/
function loadWebChatScript(url: string): Promise<void> {
logger(null, `Loading the web chat javascript from ${url}.`);

return new Promise((resolve, reject) => {
const scriptElement = document.createElement('script');
scriptElement.setAttribute('id', 'with-web-chat');
scriptElement.onload = () => resolve();
scriptElement.onerror = () => reject();
scriptElement.src = url;
document.head.appendChild(scriptElement);
});
return (window as any).wacWebChatContainerScriptPromise;
}

export { setEnableDebug, WebChatContainer, WebChatContainerProps };
export { setEnableDebug, WebChatContainer, WebChatContainerProps, ensureWebChatScript };
2 changes: 1 addition & 1 deletion src/__tests__/WebChatContainer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('WebChatContainer', () => {

await waitForWebChat(findAllByPlaceholderText);
// This second configuration should display the close and restart button.
await waitForFind('End conversation and close the chat window', findAllByLabelText);
await waitForFind('End chat and close the window', findAllByLabelText);
});

it('tests that the component renders correctly when mounted, unmounted and re-mounted', async () => {
Expand Down
20 changes: 2 additions & 18 deletions src/withWebChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import React from 'react';
import { WithWebChatConfig, OriginalProps, ForwardedRefProps, WithWebChatProps } from './types/WithWebChatTypes';
import { WebChatConfig } from './types/WebChatConfig';
import { WebChatInstance } from './types/WebChatInstance';
import { ensureWebChatScript } from './WebChatContainer';

const DEFAULT_BASE_URL = 'https://web-chat.global.assistant.watson.appdomain.cloud';

Expand Down Expand Up @@ -140,7 +141,7 @@ function withWebChat(passedConfig: WithWebChatConfig = {}) {
// If the script tag for web chat has not been injected on the page, do so now.
if (!loadWebChatScriptPromise) {
logger('appending web chat scripts to body');
loadWebChatScriptPromise = loadWebChatScript(webChatConfig, config.baseUrl);
loadWebChatScriptPromise = ensureWebChatScript(webChatConfig, config.baseUrl);
}

loadWebChatScriptPromise
Expand Down Expand Up @@ -256,21 +257,4 @@ class Deferred<T> {
}
}

// Inject WatsonAssistantChatEntry.js on the page and return a promise that resolves successfully onload.
function loadWebChatScript(webChatConfig: WebChatConfig, baseUrl: string): Promise<void> {
const src = `${baseUrl.replace(/\/$/, '')}/versions/${
webChatConfig.clientVersion || 'latest'
}/WatsonAssistantChatEntry.js`;

return new Promise((resolve, reject) => {
const scriptElement = document.createElement('script');
scriptElement.setAttribute('id', 'with-web-chat');
scriptElement.setAttribute('async', 'true');
scriptElement.onload = () => resolve();
scriptElement.onerror = () => reject();
scriptElement.src = src;
document.head.appendChild(scriptElement);
});
}

export { withWebChat };

0 comments on commit 4220724

Please sign in to comment.