Skip to content

JSInitializer.importInitializersAsync doesn't respect initializerArguments #44586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
T-mp opened this issue Oct 17, 2022 · 19 comments
Open
1 task done

JSInitializer.importInitializersAsync doesn't respect initializerArguments #44586

T-mp opened this issue Oct 17, 2022 · 19 comments
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one
Milestone

Comments

@T-mp
Copy link

T-mp commented Oct 17, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

"JSInitializer.importInitializersAsync" always loads relative to "document.baseURI" and ignores "initializerArguments".

Expected Behavior

"JSInitializer.importInitializersAsync" uses "initializerArguments.loadBootResource", same as in "Blazor.start", and uses "document.baseURI" only as a fallback.

Steps To Reproduce

No response

Exceptions (if any)

No response

.NET Version

7.0.100-rc.2.22477.23

Anything else?

No response

@javiercn javiercn added the area-blazor Includes: Blazor, Razor Components label Oct 17, 2022
@javiercn
Copy link
Member

@T-mp thanks for contacting us.

This is by design. Initializers are not exclusive to Blazor webassembly. There is no generic loadBootResource. In addition to that, initializers can alter loadBootResource in the Blazor Options so they themselves can't (and shouldn't) rely on it.

@javiercn javiercn added question ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. labels Oct 17, 2022
@ghost ghost added the Status: Resolved label Oct 17, 2022
@T-mp
Copy link
Author

T-mp commented Oct 18, 2022

My problem is that in the function "adjustPath" (line 16ff) "document.baseURI" is always set before the URL. Due to this behaviour, integration into applications that are located on a different host than the component is not possible.

If "JSInitializers.ts" is supposed to be independent of Blazor, why is "BlazorInitializer" used in line 25 and "typeof Blazor" line 40?

I think, since the file is compiled into "blazor.webassembly.js" and types of Blazor are used, checking if "loadBootResource" is present (and if so, also using it) would be justifiable.

Two gatekeepers would not interfere here but would extend the possibilities of use.

Suggested change (adjustPath start at line 16):

    function adjustPath(path: string): string {
        if (t.length > 0 && t[0].loadBootResource) {
            return t[0].loadBootResource("libraryInitializers","",e,"");
        }
        if (e.startsWith("https://") || e.startsWith("http://")) {
            return e;
        }
        // This is the same we do in JS interop with the import callback
        const base = document.baseURI;
        path = base.endsWith('/') ? `${base}${path}` : `${base}/${path}`;
        return path;
    }

The call to "loadBootResource" probably still needs to be adapted.
And the query for absolute URIs is also untested, created in this comment.

I refer to the version: https://github.com/dotnet/aspnetcore/blob/231cc287ef848dfc90dab9b3a1eeb7bdbf243d57/src/Components/Web.JS/src/JSInitializers/JSInitializers.ts

@javiercn
Copy link
Member

If "JSInitializers.ts" is supposed to be independent of Blazor, why is "BlazorInitializer" used in line 25 and "typeof Blazor" line 40?

Independent of the Blazor flavor, not of Blazor itself.

@javiercn
Copy link
Member

Due to this behaviour, integration into applications that are located on a different host than the component is not possible.

I am somewhat ok with checking for an absolute URL and returning it directly, I think that is acceptable.

        if (t.length > 0 && t[0].loadBootResource) {
            return t[0].loadBootResource("libraryInitializers","",e,"");
        }

This part I am not, since this is shared source between webassembly, server and webview and we want to avoid differentiation as much as possible.

It would be great if you can include some more details about the scenario you are trying to enable as it will help to prioritize this issue.

Would you not have this same problem when you call import from JS interop?

@javiercn javiercn added the Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. label Oct 18, 2022
@ghost
Copy link

ghost commented Oct 18, 2022

Hi @T-mp. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

@javiercn javiercn removed question ✔️ Resolution: Answered Resolved because the question asked by the original author has been answered. Status: Resolved labels Oct 18, 2022
@T-mp
Copy link
Author

T-mp commented Oct 18, 2022

OK, with excluding global URLs in the "aspnetcore/src/Components/Web.JS/src/JSInitializers/JSInitializers.ts" in the "adjustPath" function

    function adjustPath(path: string): string {
        if (e.startsWith("https://") || e.startsWith("http://")) {
            return e;
        }
        // This is the same we do in JS interop with the import callback
        const base = document.baseURI;
        path = base.endsWith('/') ? `${base}${path}` : `${base}/${path}`;
        return path;
    }

And a change in the aspnetcore/src/Components/Web.JS/src/JSInitializers/JSInitializers.WebAssembly.ts which is for WebAssembly. Which does the mapping, the function would be complete.

export async function fetchAndInvokeInitializers(bootConfig: BootJsonData, options: Partial<WebAssemblyStartOptions>): Promise<JSInitializer> {
    const initializers = bootConfig.resources.libraryInitializers;
    const jsInitializer = new JSInitializer();
    if (initializers) {
        var libUrls = Object.keys(initializers);
        if (options && options.loadBootResource) {
            libUrls = libUrls.map(libRelUrl => {
                var urlResult = options.loadBootResource("libraryInitializers", libRelUrl, libRelUrl, "");
                if ("string" == typeof urlResult)
                    return urlResult;
                else if (urlResult)
                    throw new Error(`For a 'libraryInitializers' (${libRelUrl}) resource, custom loaders must supply a URI string.`)
                return libRelUrl;
            });
        }
        await jsInitializer.importInitializersAsync(libUrls, []);
    }

    return jsInitializer;
}

The mapping in the interop is different:

       if (typeof url === "string" && url.startsWith("./")) {
           url = document.baseURI + url.substr(2);
       }

So has the possibility of not being changed.
But it is not needed in our project.

If these changes are acceptable, you don't need to think your way into a medium complex project either, and I'll save myself any potential copyright issues ;-)
If you have any questions, I'm of course happy to help.

@ghost ghost added Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. and removed Needs: Author Feedback The author of this issue needs to respond in order for us to continue investigating this issue. labels Oct 18, 2022
@T-mp
Copy link
Author

T-mp commented Oct 18, 2022

I have made the adjustments in T-mp/aspnetcore/tree/Bug44586 should I start a pull request?

@javiercn
Copy link
Member

@T-mp is the reason you want to pass the initializer through options.loadBootResource that you want to transform the path from a relative URL into an absolute URL?

@T-mp
Copy link
Author

T-mp commented Oct 19, 2022

@javiercn Partially, I would like to specify the configuration of where the resources are loaded from only once, or at least in a central place. And options.loadBootResource is needed for Blazor.Start to achieve initialization from our server.
In my scenario, the resources are on another server. We only have control over the server on which the WebComponents are hosted. The embedding pages are known to us, but apart from the URL and the tag for the WebComponent we cannot influence them (hence #44588 -> #38128). It is therefore essential that all required resources are loaded from our server.

@javiercn
Copy link
Member

@T-mp We'll discuss this issue within the team and evaluate if this is something that we want to take.

The problem with using loadBootResource is that any other initializer is allowed to change it. In fact, it is one of the reasons initializers exist, so using it to load other initializers is not a great fit.

@javiercn javiercn removed the Needs: Attention 👋 This issue needs the attention of a contributor, typically because the OP has provided an update. label Oct 20, 2022
@mkArtakMSFT mkArtakMSFT added the enhancement This issue represents an ask for new feature or an enhancement to an existing one label Oct 20, 2022
@mkArtakMSFT mkArtakMSFT added this to the Backlog milestone Oct 20, 2022
@ghost
Copy link

ghost commented Oct 20, 2022

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@T-mp
Copy link
Author

T-mp commented Oct 24, 2022

@javiercn If I change the blazor.boot.json -> libraryInitializers to absolute paths in loadBootResource when loading, the change in JSInitializers.WebAssembly.ts is not necessary.

@T-mp
Copy link
Author

T-mp commented Oct 26, 2022

Imo, the smallest change that makes sense would be: commit f642e5a

diff --git a/src/Components/Web.JS/src/JSInitializers/JSInitializers.ts b/src/Components/Web.JS/src/JSInitializers/JSInitializers.ts
index 4cc1b035eefb..40162a92dfdf 100644
--- a/src/Components/Web.JS/src/JSInitializers/JSInitializers.ts
+++ b/src/Components/Web.JS/src/JSInitializers/JSInitializers.ts
@@ -15,7 +15,11 @@ export class JSInitializer {
     await Promise.all(initializerFiles.map(f => importAndInvokeInitializer(this, f)));
 
     function adjustPath(path: string): string {
-      // This is the same we do in JS interop with the import callback
+      if (e.startsWith("https://") || e.startsWith("http://")) {
+        return e;
+      }
+      // This is the same we do in JS interop with the import callback.
+      // But there the URL is only changed if it starts with "./"!
       const base = document.baseURI;
       path = base.endsWith('/') ? `${base}${path}` : `${base}/${path}`;
       return path;

@javiercn
Copy link
Member

@T-mp I am fine with the change you suggest #44586 (comment).

@T-mp
Copy link
Author

T-mp commented Feb 1, 2023

@javiercn Should I start a pull request? (With f642e5a #44586 (comment))

@jonathonm319
Copy link

@javiercn @T-mp I'm curious if this was taken care of or if there is a work around for this issue. I am running into a similar problem as the one stated initially in this issue.

@T-mp
Copy link
Author

T-mp commented Aug 17, 2023

@jonathonm319 As far as I know so far:
Save the original ".js", do the manipulation as in #44586 and save the result in the wwwroot...

But, attention: after every update of .NET you have to repeat it! (at least check) Otherwise errors can occur.

@dotnet dotnet deleted a comment Nov 12, 2023
@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@wtgodbe wtgodbe removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@dotnet-policy-service dotnet-policy-service bot added the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 6, 2024
@wtgodbe wtgodbe removed the pending-ci-rerun When assigned to a PR indicates that the CI checks should be rerun label Feb 13, 2024
@dotnet dotnet deleted a comment from dotnet-policy-service bot Feb 13, 2024
@dotnet dotnet deleted a comment from dotnet-policy-service bot Feb 13, 2024
@gunlaw-Barbri
Copy link

@T-mp where in the wwwroot do you put it? This function/file seems to be bundled in blazor.webassembly.js so I'm not sure how that would be respected.

@T-mp
Copy link
Author

T-mp commented Mar 22, 2024

@gunlaw-Barbri Sorry, I don't remember that (it's been a while).
I took the path from the browser. (Possibly overwrite the path in program.cs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components enhancement This issue represents an ask for new feature or an enhancement to an existing one
Projects
None yet
Development

No branches or pull requests

6 participants