Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Chrome Extension with Blazor WASM - The Integration
.NET profile imageJustin Yoo
Justin Yoo for.NET

Posted on • Edited on • Originally published atdevkimchi.com

     

Chrome Extension with Blazor WASM - The Integration

In myprevious post, I've walked through how to migrate a JavaScript-basedChrome extension toBlazor WASM with minimal code changes. Although it's successfully migrated to Blazor WASM, it doesn't fully use theJavaScript Interoperability (JS interop) feature, which is the powerful feature of Blazor WASM. I'm going to take this feature throughout this post.

You can download the sample Chrome extension from this GitHub repository:

GitHub logo devkimchi / blazor-wasm-chrome-extension

This provides sample codes for a Chrome Extension app built on Blazor WASM

Blazor WASM Browser Extension Sample

This provides sample codes for a cross-browser extension app built on Blazor WASM. This sample app originally started for building a Chrome extension with Blazor WASM, but it now does the cross-browser support including Chromium-based browsers and Mozilla FireFox.

Acknowledgement

This sample code includesMozilla'sWebExtensionbrowser API Polyfill, which is licensed underMPL 2.0.

Getting Started

  1. Build the app

    dotnet build.
    Enter fullscreen modeExit fullscreen mode
  2. Publish the app

    dotnet publish ./src/ChromeExtensionV2/ -c Release -o published
    Enter fullscreen modeExit fullscreen mode
  3. Run PowerShell script

    ./Run-PostBuild.ps1
    Enter fullscreen modeExit fullscreen mode
  4. Register the extension to your Chromium-based browser likeChrome orEdge, orMozilla FireFox.

  5. Visit any website onhttps://developer.chrome.com,https://developer.mozilla.org orhttps://docs.microsoft.com.

  6. Run the extension by clicking the icon at the top of your web browser.

Chrome Extension – Before JS Interop

Theindex.html file written in theprevious post looks like the following. It loadsblazor.webassembly.js first with theautostart="false" option, followed by loadingjs/main.js through the function call. Thejs/main.js reference is replaced withjs/options.js orjs/popup.js during the artifact generation process.

<!DOCTYPE html><htmllang="en">...<body><divid="app">Loading...</div>    ...<!-- Add the 'autostart' attribute and set its value to 'false' --><scriptsrc="_framework/blazor.webassembly.js"autostart="false"></script><!-- ⬇️⬇️⬇️ Add these lines ⬇️⬇️⬇️ --><script>Blazor.start().then(function(){varcustomScript=document.createElement('script');customScript.setAttribute('src','js/main.js');document.head.appendChild(customScript);});</script><!-- ⬆️⬆️⬆️ Add these lines ⬆️⬆️⬆️ --></body></html>
Enter fullscreen modeExit fullscreen mode

I'm not happy with this JS loading due to the two reasons below:

  1. I have to explicitly give the option ofautostart="false" while loading theblazor.webassembly.js file, which is extra to the bootstrapper.
  2. I have to appendjs/main.js through the Promise pattern afterBlazor.start(), which is another extra point to the bootstrapper.

Can we minimise this modification from the originalindex.html file and use more JS Interop capabilities here so that it can be more Blazor-ish?

Chrome Extension – JS Interop Step #1

Let's update theindex.html file. Unlike the previous update, remove the JS part calling theBlazor.start() function. Loadjs/main.js before loadingblazor.webassembly.js. Remove theautostart="false" attribute as well.

<!DOCTYPE html><htmllang="en">...<body><divid="app">Loading...</div>    ...<!-- ⬇️⬇️⬇️ Add this line ⬇️⬇️⬇️ --><scriptsrc="js/main.js"></script><!-- ⬆️⬆️⬆️ Add this line ⬆️⬆️⬆️ --><scriptsrc="_framework/blazor.webassembly.js"></script></body></html>
Enter fullscreen modeExit fullscreen mode

Originally thejs/main.js file was blank, but this time let's add the following JS function that appends anotherscript tag to load the given JS file reference.

functionloadJs(sourceUrl){if(sourceUrl.Length==0){console.error("Invalid source URL");return;}vartag=document.createElement('script');tag.src=sourceUrl;tag.type="text/javascript";tag.onload=function(){console.log("Script loaded successfully");}tag.onerror=function(){console.error("Failed to load script");}document.body.appendChild(tag);}
Enter fullscreen modeExit fullscreen mode

Update thePopup.razor file like below:

  1. Add the@inject declaration for theIJSRuntime instance as a dependency.
  2. Call theJS.InvokeVoidAsync method to load thejs/popup.js file by invoking theloadJs function from thejs/main.js file.
@* Popup.razor *@@page "/popup.html"@* Inject IJSRuntime instance *@@inject IJSRuntime JS...@code {    protected override async Task OnAfterRenderAsync(bool firstRender)    {        if (!firstRender)        {            return;        }        var src = "js/popup.js";        // Invoke the `loadJs` function        await JS.InvokeVoidAsync("loadJs", src).ConfigureAwait(false);    }}
Enter fullscreen modeExit fullscreen mode

Update theOptions.razor file in the same way.

@* Options.razor *@@page "/options.html"@* Inject IJSRuntime instance *@@inject IJSRuntime JS...@code {    protected override async Task OnAfterRenderAsync(bool firstRender)    {        if (!firstRender)        {            return;        }        var src = "js/options.js";        // Invoke the `loadJs` function        await JS.InvokeVoidAsync("loadJs", src).ConfigureAwait(false);    }}
Enter fullscreen modeExit fullscreen mode

Now, we don't need the reference replacement part in the PowerShell script. Let's comment them out.

# Run-PostBuild.ps1...# Update-FileContent `#     -Filename "./published/wwwroot/popup.html" `#     -Value1 "js/main.js" `#     -Value2 "js/popup.js"# Update-FileContent `#     -Filename "./published/wwwroot/options.html" `#     -Value1 "js/main.js" `#     -Value2 "js/options.js"
Enter fullscreen modeExit fullscreen mode

Build and publish the Blazor WASM app, then run the PowerShell script to get ready for the extension loading. Once reload the extension, it works with no issue. TheloadJs function is the key that takes advantage of the JS Interop feature.

However, I'm still not happy with addingjs/main.js toindex.html. Can we also remove this part from the file and use the JS Interop feature instead?

Chrome Extension – JS Interop Step #2

Let's getindex.html back to the original state when a bootstrapper creates the file. Then, all we can see inindex.html is theblazor.webassembly.js file reference.

<!DOCTYPE html><htmllang="en"><head><metacharset="utf-8"/><metaname="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/><title>ChromeExtensionV2</title><basehref="/"/><linkhref="css/bootstrap/bootstrap.min.css"rel="stylesheet"/><linkhref="css/app.css"rel="stylesheet"/><linkhref="ChromeExtensionV2.styles.css"rel="stylesheet"/></head><body><divid="app">Loading...</div><divid="blazor-error-ui">        An unhandled error has occurred.<ahref=""class="reload">Reload</a><aclass="dismiss">🗙</a></div><scriptsrc="_framework/blazor.webassembly.js"></script></body></html>
Enter fullscreen modeExit fullscreen mode

Then, add theexport declaration in front of theloadJs function in thejs/main.js file.

exportfunctionloadJs(sourceUrl){...}
Enter fullscreen modeExit fullscreen mode

UpdatePopup.razor like below.

...varsrc="js/popup.js";// Import the `js/main.js` filevarmodule=awaitJS.InvokeAsync<IJSObjectReference>("import","./js/main.js").ConfigureAwait(false);// Invoke the `loadJs` functionawaitmodule.InvokeVoidAsync("loadJs",src).ConfigureAwait(false);
Enter fullscreen modeExit fullscreen mode

The same change should also be applicable toOptions.razor. And finally, update themanifest.json below because we no longer need the hash key forpopup.js andoptions.js.

{"manifest_version":2,"version":"1.0","name":"Getting Started Example (Blazor WASM)","description":"Build an Extension!",..."content_security_policy":"script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval' 'sha256-v8v3RKRPmN4odZ1CWM5gw80QKPCCWMcpNeOmimNL2AA='; object-src 'self'",...}
Enter fullscreen modeExit fullscreen mode

Build and publish the app, and run the PowerShell script against the artifact. Then, reload the extension, and you will see the same result.


So far, we've walked through how to take more advantage of theJS Interop feature thatBlazor WASM offers to migrate the existing Chrome extension to Blazor WASM. What could be the potential merits of this exercise?

  1. We never touch any bootstrapper codes that Blazor WASM generate for us.
  2. If necessary, we load JavaScript for each page using the JS Interop feature. During this practice, C# handles all the JS codes.

Then, does this exercise only brings you benefits? Here are a couple of considerations:

  1. The code gets overly complex. If we simply import the JavaScript files through theindex.html/popup.html/options.html, we don't need to do this exercise.
  2. Not everytime the dynamic JS loading is useful. It has trade-offs. If you don't want to touch the bootstrapper files, then try this approach discussed in this post. But if you do touch the bootstrapper files, then this dynamic JS loading approach may be unsuitable.

Overall, if we use more JS Interop features appropriately, we can build the Blazor WASM app more effectively, which will be another option for building Chrome extensions. In thenext post, I'm going to discuss cross-browser compatibility for this Blazor WASM-based browser extension.

Do you want to know more about Blazor?

Here are some tutorials for you.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

New to .NET and don't know where to start? You can try .NET in your browser, at the console on your machine, or by building the app of your choice.

More from.NET

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp