6

TL;DR

In case you aren't into reading walls of text, here's the question in a nutshell:

Is there an API in LWC that can get a static resource URL dynamically in an LWR site? Please note that, in LWR sites, the pattern for a static resource URL has changed, so old tricks like using a dummy or stand-in static resource no longer work. Notice the use of a Static Resource's Record Id rather than its Name:

<SITE_PREFIX> /webruntime/org-asset/ <UNKNOWN_10_DIGIT_HEX_VALUE> /resource/ <STATIC_RESOURCE_RECORD_ID>

Full Context

What I Already Know

Visualforce

Way back in "ye olden times" (circa 2013), getting a static resource URL was pretty simple.

In Visualforce, you could get a static resource URL with a merge field in your markup file:

{!$Resource.ns__ResourceName}

This wasn't "dynamic", but then again Visualforce wasn't really made for dynamic client-side rendering.

If you needed to construct the URL in Javascript, you could build it by using the following pattern:

<SITE_PREFIX> /resource/ <OPTIONAL_MOD_STAMP/> ns__ResourceName </OPTIONAL_ZIP_RESOURCE_PATH>

Lightning (Aura)

In Aura we gained a client-side function to get a Static Resource URL. It was a bit bulky, but it got the job done:

$A.get('$Resource.ns_ResourceName');

This also worked for dynamic URL fetching, e.g.:

function getStaticResourceUrl(staticResourceName) {
  return $A.get('$Resource.' + staticResourceName);
}

Lightning Web Components

With LWC we can now import static resource URLs:

import staticResourceURL from "@salesforce/resourceUrl/resourceName";

In many ways I prefer this syntax as it encourages reuse of a constant rather than making redundant function calls.

However, in LWC there does not appear to be any dynamic equivalent to "importing" a static resource URL.


Why I Need a Dynamic Function in LWC

Why I Need a Dynamic Function in the First Place

In my case, there are some static resources which I can predict (e.g. JS files), but there are others which are provided by the user via configuration (e.g. JSON configuration files).

The Old Tricks Break in LWR

Despite all the various ways of generating a URL in Visualforce, Aura and LWC, the structure of the URL was always the same, so in cases where I needed to construct a URL I could always fall back to building it myself (where I could generate my own modstamp if necessary):

`${sitePrefix}/resource/${modstamp}${resourceName}${path}`

However, this trick appears to break in LWR sites. I noticed that my new LWC component was not loading correctly and throwing a bunch of errors when I tried to use it in an LWR site. I believe this is, at least partly, due to those static resource URLs. Whereas a static resource URL in a regular Lightning record page has the same shape as mentioned above, in LWR they've changed the URL to a new format:

<SITE_PREFIX> /webruntime/org-asset/ <UNKNOWN_10_DIGIT_HEX_VALUE> /resource/ <STATIC_RESOURCE_RECORD_ID>

The worst part of it is that the URL now uses a Record Id, as in 0814A000000lXJu. The static resource name is no longer used anywhere in the URL. Meaning I can't even use a stand-in static resource and then edit the name later. For example, staticResourceURL.replace('resourceName', dynamicResourceName) doesn't change the URL because "resourceName" isn't located anywhere in the string.

It looks like I am going to have to refactor quite a bit of code to make getting a static resource URL an asynchronous callout but, to make matters worse, I can't find any built-in asynchronous function in LWC to create an appropriate static resource URL for me. I'm hoping that I've merely overlooked one (somehow) and that I'm not going to have roll my own server-side URL builder that will cost me a SOQL query for each static resource I need.

1 Answer 1

2

NOT AN ANSWER - the comment box is too small for my response...

I did a console.log on video:

import Video from "@salesforce/contentAssetUrl/Video";

Then traced the files back a little and found this:

(function() { LWR.define('@salesforce/contentAssetUrl/Video', ['exports', '@app/basePath', '@app/versionKey'], (function (exports, basePath, versionKey) {

    function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }

    var basePath__default = /*#__PURE__*/_interopDefaultCompat(basePath);
    var versionKey__default = /*#__PURE__*/_interopDefaultCompat(versionKey);

    var _2alh7xtzmse9ip42njuezcz46sinysb5b = `${basePath__default.default}/webruntime/org-asset/${versionKey__default.default}/file-asset/03S250000009QVg`;

    exports.default = _2alh7xtzmse9ip42njuezcz46sinysb5b;

    Object.defineProperty(exports, '__esModule', { value: true });

}));
})();

So far I have been unable to work out what the @app/versionKey actually is though... I tried importing it in a few different ways (replacing @app with "@salesforce/community/versionKey", etc...), but was unsuccessful each time, the only thing I can potentially think to do for now, it to have an LWC that imports a generic Static Resource/Content Asset and maybe use some JS to strip out the rest of the URL leaving you with just that.

At least that way you can put the LWC on a page, select the Static Resource/Content Asset that you want and have it auto generate the full URL for you.

I tried using the same versionKey across 2 orgs and it did not like it by the way, so it's definitely something unique to the Org. Something else I haven't checked is whether this is related to releases.

*** UPDATE *** I actually just stumbled across this: enter image description here

The path of my site is /video and this is the main file that renders the site. I'll keep digging and update if I find anything else!

*** ANOTHER Update ***

I realised the verisonKey that is being used is appended to the end of the CSS URL in the Header Markup:

<link rel="stylesheet" href="{ basePath }/assets/styles/salesforce-lightning-design-system.min.css?{ versionKey }" />

I can't work out how to access the versionKey outside of the Header Markup, however I did just set it as a global var and it seems to be usable in other places now:

<script>
    window.versionKey = '{ versionKey }';
</script>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .