-
Notifications
You must be signed in to change notification settings - Fork 25.3k
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
New JS interop #27083
New JS interop #27083
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it overall :)
Let's add @maraf as another reviewer. I don't have permissions to do that.
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
Updates made, and I'll call this a 'successful draft,' given that apparently I didn't butcher the API 😆. I'll number these for easy responses ... Updates
Remaining ❓ on module name 💥
|
dotnet GC would collect the proxy anyway at some point. I would not complicate the docs about
I just wrote this test, to make sure it's working as expected and it is working for me. [Fact]
public async Task MultipleImportAsync()
{
var first = await JSHost.ImportAsync("JavaScriptTestHelper", "./JavaScriptTestHelper.mjs");
var second = await JSHost.ImportAsync("JavaScriptTestHelper", "./JavaScriptTestHelper.mjs");
Assert.NotNull(first);
Assert.NotNull(second);
Assert.Equal("object", first.GetTypeOfProperty("instance"));
var instance1 = first.GetPropertyAsJSObject("instance");
var instance2 = second.GetPropertyAsJSObject("instance");
Assert.Equal(instance1, instance2);
} Could you please share more details and also the error you get ? Also, it should be enough to call |
It's against the normal disposal pattern that we pitch. I suspect that this would be more important in a server-side scenario that we aren't covering here. If it's ok with you, let me get Dan's feedback on it just to make sure. I just want to ask because we'd normally guide this way. If we don't show it, we might still leave a note that says something like ... 'client-side code that assigns the
The following class results if the reader attempts to work through both examples with the same I kind'a vaguely feel like I know why this isn't working. The collocated JS files are TWO modules in these examples ... is that right? ... and this C# class is giving both of them the same module name ... and it's then it seems like it's choking on that setup 💥. Anyway ... here's the way I was originally trying to make it work ... using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
[SupportedOSPlatform("browser")]
public partial class Interop
{
[JSImport("getMessage", "Interop")]
internal static partial string GetWelcomeMessage();
[JSImport("setMessage", "Interop")]
internal static partial void SetWelcomeMessage();
[JSExport]
internal static string GetMessageFromDotnet()
{
return "¡Hola desde Blazor!";
}
} The @page "/call-dotnet"
@using System.Runtime.InteropServices.JavaScript
<h1>.NET JS Import/Export Interop (Call .NET)</h1>
<p>
<span id="result">.NET method not executed</span>
</p>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (OperatingSystem.IsBrowser() && firstRender)
{
await JSHost.ImportAsync("Interop", "../Pages/CallDotNet.razor.js");
Interop.SetWelcomeMessage();
}
}
} ... and the collocated JS file contains ... export async function setMessage() {
const { getAssemblyExports } = await globalThis.getDotnetRuntime(0);
var exports = await getAssemblyExports("BlazorSample.dll");
document.getElementById("result").innerText = exports.Interop.GetMessageFromDotnet();
} The first example (call JS) from the first section, still works in the app 👍. The 2nd example melts down 💥 with ...
We can say in the text the reason that the module is named something else for the 2nd example ... whatever that reason is, but I also think we should use something other than |
oh ... and WRT ...
Do you mean across components??? That seems kind'a strange because one wouldn't know which component a user would request first. Wouldn't that be fragile? ... or should the module be set up for loading when Blazor itself starts? I wonder if that aspect is going to need to be explained out further in the text ... i.e. ... they can do it the way that the topic shows it for a one-off module used with one component ... one C# interop class, one dedicated module. If they have a module that's set up to work across components, then it should be loaded at Blazor's start? ... is that right? 🤔 ... I think we'd go with TWO interop C# classes with different module names for the TWO components between these sections ... the TWO collocated JS files. It's ideal if these examples are simple and clear and ✨ Just Work!™ ✨😄 . Then, we can have a new section for a single module that exports JS for multiple components. Perhaps, that section does NOT have a fully-working example but just places some partial code examples to show what to do in that case. This is a typical doc problem ... several ways to do things but a desire to make the introductory content accessible to devs of all levels and new-to-.NET folks. |
If you have same JS file on the same absolute URL across blazor components, it's still the same ES6 module from JS perspective. the URL is relative to |
Yes, but is the reason that my first attempt fails because the JS exports fail to work in the 2nd example because I named the module the same thing in the C# class but use two collocated JS files? It seems like that's what the problem is. It's just my lack of understanding of JS modules in the context of the new import/export API that tripped me up. I think my last idea makes the most sense. Each section here gets it's own "Interop" C# class with different class names ... a collocated module for each component (separate JS files) ... and uses a different module name for each. ....... I think 🤔. That's the base case ... the simplest way to demo these approaches SxS in a single test app. Then ... I think we'll need a new section on using a single module across components (i.e., NOT using collocated JS). There will be an import/export at Blazor start with ONE module ... one module name ... and hypothetically no wipeout 💥 that way. I'm just thinking out loud, so please feel free to stop me before I embarrass myself further! 🤣 |
Last commit merely sets up the two sections for separate classes and separate modules. That's at least not going to break when placed into the same test app. Next, I'll see about working up a section that uses a single module across components. I won't necessarily use fully-working example code tho. I might just call out the deltas from the preceding sections that make it work. UPDATE: I think I have a version of this now. I'll add a section to cover the scenario to see how it composes. But ... WRT ...
I still wouldn't know which component is requested first, so I still call Let's see how this all composes and then we can call for my immediate 💀 and dismemberment 🔪 when see what I put here 😄. Well, it is that time of year! 🎃 UPDATE: Next commit lays a new section with the single module case, but I did call |
are you also updating the samples repo at the same time ? Is there PR with full code I could look at ? |
No, that will come later. For now, it's all just inline code blocks in the topic and a local test app that I'm working with. I normally let things settle on the first release of new bits before moving examples into the snippet sample apps. I can put my test app up on GH if you like. |
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
Here it is ... ignore the name of the app, as that goes back to Day 1 when I didn't know exactly what this was ... |
... and it's obvious from that that I don't know how to load the module from one spot at app startup and avoid the calls to |
Perhaps you could rename the In my demo I have
and then in JS I could have
|
Yes! Good idea. I was trying to use a single class at first, but the new way here for the first two sections will compose even better that way. |
Hold off on the last commit tho. I probably need to refactor that again. I'm running out of time today to continue. We'll probably need to pick back up on Tuesday morning with the updates. No worries tho AFAIK ... I don't think we're late in any sense. |
mmmmm ... yeah ... I'm running into 😈 namespace collision gremlins 😈 because I can't have the component share a class name with the C# interop class. I didn't name things very well 🙈 on a quick pass ... I don't think I ended up with something following your example. Yeah ... let me pick back up with this on Tuesday morning. I'll fix it all up along the lines of your last suggestion. If you know how I load a module to avoid the two |
This is all good, you are learning from trying! |
Yes! That's at least one reason why they bother even keeping me around here! 🤣 |
Co-authored-by: Daniel Roth <daroth@microsoft.com>
…terop.md Co-authored-by: Daniel Roth <daroth@microsoft.com>
@danroth27 ... I think there are just two quick items to resolve and this can be merged ... Cache BustingCache busting guidance wasn't finalized. Do you want me to strike that section? Naming consistency for the new JS interop".NET JavaScript Everywhere, we'd call this tech (initial mention) ... JavaScript (JS) ... and then shortened thereafter to either ...
... or just ... JS interop ... if we can get away with it. I was naming it with " |
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
aspnetcore/blazor/javascript-interoperability/import-export-interop.md
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more minor comments, but otherwise this looks good to me.
@guardrex I didn't see this content in the PR anymore, so I assume you already removed it? |
@guardrex Can you clarify for me what title change you are proposing? |
I just had a placeholder for it at Line 49, UPDATE: I just removed it on the last commit.
Yes ... it's just up above ☝️ ... asking if we should remove the ".NET" part everywhere from the naming to make it consistent between the two articles. ☝️ #27083 (comment) ☝️ |
Co-authored-by: Daniel Roth <daroth@microsoft.com>
The current title for this article is: ".NET JavaScript Are you proposing that the name of this article should drop the ".NET" for consistency? So the new title would be: "JavaScript |
Yes, that's right. I've made the change. It's consistent with the other article now. This is the first Blazor doc to get file-scoped namespaces. Updates will roll into all of the docs over time. I noticed that MS/you aren't fully collapsing the Why not save one more line with file-scoped namespaces? (dotnet/aspnetcore #44676) For this PR, I do it the PU-way ... e.g. ... using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
namespace BlazorSample.JavaScriptInterop;
[SupportedOSPlatform("browser")]
public partial class Interop
{
...
} If you change your mind, I'll patch these up later. 🤔Personally ... just for my own personal use ... I kind'a favor at the moment going top-of-file with it ... namespace BlazorSample.JavaScriptInterop;
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;
[SupportedOSPlatform("browser")]
public partial class Interop
{
...
} That locates it quickly, which is all that placing it on a line with space around it seems to accomplish. |
Addresses #27016
Addresses #26364
Internal Review Topic
Notes
dotnet/blazor-samples
.❓ on this one: I'd prefer if the examples compose in such a way that both the import example and the export example can live SxS in the same developer test app. I provide cut-'n-paste, fully working examples to readers whenever possible, and they're very popular. I ran into a problem tho ... I can't name the export module
Interop
and place it into theInterop.cs
/Interop
class file. It fails. 💥 I have to name it something else ... I useInterop2
on the PR ... to make it work. I don't understand why tho. Anyway, I'm 👂 for your help on that point.For Dan later ...
IJSRuntime
eventually?[JSImport]
/[JSExport]
interop" just to have something to distinguish it, based loosely on your blog post comments. Even with the name that I gave it, it's a bit easier to see that this is a separate interop approach if it's in its own topic.