Daddoon / Blazor.Polyfill

Blazor server-side Polyfills and fixes for Internet Explorer 11 & Edge Legacy
MIT License
120 stars 19 forks source link

Blazor.Polyfill[]()

Blazor server-side Polyfills and fixes for Internet Explorer 11 & Edge Legacy (EdgeHTML engine).

SUMMARY

INSTALLATION

.NET 5.0 / .NET 6.0 / .NET 7.0

Installation

BlazorPolyfill.Server NuGet package can be either found on nuget.org or from the latest release page on this repository.

NOTE: blazor.polyfill.js content will be kind of empty automatically if the detected browser, through the user-agent, is something else than Internet Explorer or Edge Legacy.

(Optional) Javascript isolation & module import support

Due to the lack ES6 and dynamic module import support on old browsers like Internet Explorer 11, some powerful functionalities like javascript isolation is not available. This cannot be polyfilled directly as it's a missing browser and language feature.

However this can be done by creating a ES5 compatible bundle library, that will mimic the dynamic import behavior at runtime.

The NuGet package BlazorPolyfill.Build has been done to make this automatic at build time.

Here are the step to install it:

Limitations

Additional options

You can configure additional options through the UseBlazorPolyfill method with a BlazorPolyfillOptions object instance or configuration delegate. Here some kind of example:

app.UseBlazorPolyfill(
    (options) => {
        options.ForceES5Fallback = false;
        options.ES5FallbackValidation = (HttpRequest request) =>
        {
            //Add your custom polyfill validation logic here.

            //The current example always validate polyfill behavior
            //but you can check User-Agent or other things
            //in the 'request' parameter.
            return true;
        };
    });

Options:

// Specify the conversion scope of Javascript files to ES5 during application lifetime.
// Read the enum description for the detailled behaviors.
// 
// Default value is ES5ConversionScope.None
//
// Here are the enum descriptions:

// If None is selected, only the blazor.server.js file will be converted to ES5.
// This is the minimum requirement and goal of this library.
// ES5ConversionScope.None = 0,

// If RazorClassLibraries is selected, only the blazor.server.js file and any Razor Class Library loaded in the project will be converted to ES5.
// Razor Class Library are any library loaded from a package that you reference through a special URI starting by '_content/' in your project.
// ES5ConversionScope.RazorClassLibrary = 1,

// If All is selected, any Javascript file will be converted to ES5
// ES5ConversionScopeAll = 2

// Additional note: If you use any third party library as Razor Class Library (RCL) for Blazor through NuGet, it's highly recommended
// to set at least the enum level to ES5ConversionScope.RazorClassLibrary, as you don't have direct control to any packaged libraries easily.

// Another note is that the ESConversionScope behavior is also linked to any ES5 fallback behavior logic, like ForceES5Fallback property or ES5FallbackValidation method.

public ES5ConversionScope ES5ConversionScope { get; set; }

// If the ForceES5Fallback parameter is set to true,
// the blazor.polyfill.js library content will always be returned
// and the blazor.server.js library will always be transpiled to ES5 with the needed fixes.
//
// If this parameter is set to false, only Internet Explorer 11 and Edge Legacy will have
// the ES5 fallback behavior.
//
// Default value is false.
public bool ForceES5Fallback { get; set; }

// Provide a method that validate if the current request should return the ES5 Fallback behavior or not.
// This can be useful if you want to extend the polyfill to some other browsers and/or conditions specific values.
// 
// Note that if ForceES5Fallback option is set to true, the ES5FallbackValidation return value
// will have no effect.
// 
// Also, Internet Explorer 11 and Edge Legacy will always return the ES5 Fallback behavior in all scenarios.
public Func<HttpRequest, bool> ES5FallbackValidation { get; set; }

// Provide a method that expose a Javascript file that must be converted to ES5, in case you
// wish to alter it before transformation.
// First parameter is the file path from request,
// Second parameter is the original file content,
// Return value is the content that will be provided for the ES5 transformer
public Func<string, string, string> BeforeES5TransformHandler { get; set; }

// Allow to bind a custom method that will be called when an internal ES5 conversion
// event fail in order to track down the cause.
// First parameter is the source file path
// Second parameter is the Blazor.Polyfill.Server exception when the exception occur
// with the innerException that thrown.
public Action<string, Exception> OnES5ConvertFailure { get; set; }

// If enabled, the polyfill library will assume that you have added the BlazorPolyfill.Build library to your project
// and will try to load the generated ES5 scripts version of your javascript modules at boot after the polyfill library
// initialization on client side.
// 
// You can customize the expected library path and name to load through JavascriptModuleImportEmulationLibraryPath property
public bool JavascriptModuleImportEmulation { get; set; }

// Get or set the value of the path location of your ES5 javascript library file that emulate your regular javascript modules,
// generated from the BlazorPolyfill.Build package. The path given will be used to load your modules after the polyfill
// initialization. Default value is: "/es5module.min.js"
public string JavascriptModuleImportEmulationLibraryPath { get; set; }

// If set to true, the returned blazor.server.js file for ES5 compatibility will be a packaged one in this library
// instead of the one generated dynamically. It's not recommended in the sense that this usage prevent the automatic update
// of the blazor.server.js library if you install newer version of Blazor Server, and would maybe add issue. This option
// is a convenience for users who cannot dynamically transpile with React.NET/Babel because of missing JS engines for their
// platform or having issue with it, typically like ARM32v7 OS's.
public bool UsePackagedBlazorServerLibrary { get; set; }

.NET 3.1

<script type="text/javascript" src="https://github.com/Daddoon/Blazor.Polyfill/raw/master/js/blazor.polyfill.min.js"></script>
<script src="https://github.com/Daddoon/Blazor.Polyfill/raw/master/_framework/blazor.server.js"></script>

...considering you have copied the file in a wwwroot/js folder.

<script type="text/javascript">
    if (/MSIE \d|Trident.*rv:/.test(navigator.userAgent)) {
        document.write('<script src="https://github.com/Daddoon/Blazor.Polyfill/raw/master/js/blazor.polyfill.min.js"><\/script>');
    }
</script>
<script src="https://github.com/Daddoon/Blazor.Polyfill/raw/master/_framework/blazor.server.js"></script>

RECOMMENDATIONS & TROUBLESHOOTING

OS & CPU Compatibilities

Not all OS's or CPU architectures are supported for the dynamic transpilation, or some environments like Azure, base Docker images, or else, may miss some required dependencies.

Everything should work out of the box on:

Theses platforms are supported but the environment requirements may have issue depending the configuration:

Theses platforms are unsupported:

What should i do if i'm on an unsupported environment ?

If you are on an unsupported environment, consider disabling the transpilation process with BlazorPolyfill, and use a packaged versions of the fixed blazor.server.js. Here are the steps:

ABOUT

Polyfills

This are the required polyfills and fixes in order to launch Blazor from Internet Explorer 11 & Edge Legacy (EdgeHTML engine).

This project is using the following polyfills internally:

Also an usage of babel-standalone through ReactJS.NET library for the alteration of the blazor.server.js library on-the-fly, in order to transpile code to ES5.

NOTE: that the blazor.polyfill.js file return an "empty" javascript content if the browser is not Internet Explorer 11 or Edge Legacy.

blazor.server.js file alteration on Internet Explorer 11 & Edge Legacy

Only using Polyfills was not sufficient in order to make it working on IE11 and Edge.

The blazor.server.js library is dynamicaly altered at the first app request. The altered returned version is ONLY returned for IE11 and Edge, other browsers will receive the regular file packaged by Microsoft.

The library is altered on the fly because the Microsoft library may update in the future in your app, and we always want to have the current latest version of the library to be modified at startup.

Some events are done before the final file result is cached on the server:

Using Telerik Blazor Component or MatBlazor on IE11

Telerik Blazor Component or MatBlazor may not work out of the box on IE11.

This is not related to a missing functionality of Blazor.Polyfill, as it is sufficient to launch Blazor on IE11 with it, but just the fact that some functionalities used by Telerik Blazor component are not available on it.

Some additional polyfills will be required in addition of Blazor.Polyfill, to make the Telerik Blazor Component library work on it.

You will need:

Using polyfill.io you could load your Blazor app like this instead:

<script type="text/javascript">
    if (/MSIE \d|Trident.*rv:/.test(navigator.userAgent)) {
        document.write('<script src="https://polyfill.io/v3/polyfill.min.js?features=Element.prototype.closest%2CIntersectionObserver%2Cdocument.querySelector%2Cfeatures=Array.prototype.forEach%2CNodeList.prototype.forEach"><\/script>');
    }
</script>
<!-- Your blazor.polyfill.js and blazor.server.js scripts -->