Hi,
I’m facing an issue with WRM caused by atlassian-webresource-webpack-plugin.
We use the webpack plugin to bundle our resources and generate the WebResource definitions for our P2 plugins. By default, the plugin has a list of built-in provided dependencies:
exports.builtInProvidedDependencies = new Map()
.set('wrm/require', (0, exports.buildProvidedDependency)('com.atlassian.plugins.atlassian-plugins-webresource-rest', 'web-resource-manager', 'WRM.require', 'wrm/require'))
.set('wrm/context-path', webresourceDep('context-path', 'WRM.contextPath', 'wrm/context-path'))
.set('wrm/data', webresourceDep('data', 'WRM.data', 'wrm/data'))
.set('wrm/format', webresourceDep('format', 'WRM.format', 'wrm/format'))
.set('wrm/i18n', webresourceDep('i18n', 'WRM.I18n', 'wrm/i18n'));
This list is added regardless of what we do. In the generated resources XML, the following dependencies are automatically added:
<dependency>com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path</dependency>
<dependency>com.atlassian.plugins.atlassian-plugins-webresource-rest:web-resource-manager</dependency>
We include our resources using the PageBuilderService:
PageBuilderService.assembler().resources().requireContext(ResourcePhase.DEFER, "context")
I would expect that the PageBuilderService would remove duplicates and filter out the WRM stuff because it would already be used by the page. However, this is not the case. The generated batched javascript file includes the WRM stuff on top. More specifically, it includes the following context path override:
/* module-key = 'com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path', location = 'js/data/context-path.js' */
;(function() {
var contextPath = null;
function getContextPath() {
if (contextPath === null) {
contextPath = WRM.data.claim('com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path.context-path');
}
return contextPath;
}
if (typeof define === 'function') {
define('wrm/context-path', () => getContextPath);
}
// Export a global variable
WRM.contextPath = getContextPath;
// This used to be part of AUI, so preserve the legacy.
AJS.contextPath = getContextPath;
}());
As you can see, this code sets the global functions WRM.contextPath()
and AJS.contextPath()
.
This should normally not be an issue, but sometimes there is a race condition on the page load in which the same code is also executed through inclusion from other web resources (or, more notably, the host application itself). Since our code is listed as deferred, this is usually the case.
The issue is that WRM.data.claim()
only allows a specific key to be “claimed” once. When the key is claimed, the claim()
function returns the value of BAD_RETURN
:
claim(key, successcb, failurecb) {
if (!successcb && !failurecb) {
if (globalHolder._claimedData.has(key)) {
console.error(`Data with key '${key}' has already been claimed`);
return BAD_RETURN;
}
BAD_RETURN
is never defined in code, which means that it returns undefined
. This means that as soon as our code is executed, AJS.contextPath()
will now return undefined
, which results in the following broken XHR requests on the Confluence page:
https://localhost/undefined/rest/wrm/2.0/resources
I would love to be able to exclude the WRM code from my bundles, but at this point I don’t know how to achieve that other than running some XSLT during resource generation.
To be honest, I was expecting the PageBuilderService to know that the WRM stuff was already included on the page and remove it from our bundled code, or some other fancy trick. But that doesn’t seem to be the case.
@mkemp is this something you can help me with?