DEV Community

Cover image for A polyfill for Umbraco packages
Lee Kelleher
Lee Kelleher

Posted on • Edited on

A polyfill for Umbraco packages

Update: 2023-05-23. Due to the lack of interest, the Umbraco Polyfill package has now been deprecated. The source code is available on GitHub: https://github.com/leekelleher/umbraco-polyfill


If you are unfamiliar with the term polyfill in web development, here is the definition from MDN...

A polyfill is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.

https://developer.mozilla.org/en-US/docs/Glossary/Polyfill

Typically, polyfills are referenced in the context of front-end web development, but they could also be applied to server-side APIs.


I hear you asking: What does this have to do with Umbraco packages?

This time last year, I'd started migrating my Umbraco package, Contentment to support Umbraco 9 on ASP.NET Core 5. My initial approach was to drop support for Umbraco 8 to focus exclusively on Umbraco 9. A decision that niggled me.

During the code migration, I'd discussed with fellow Umbraco package developers about multi-targeting .NET frameworks within the same codebase, and indeed it was possible, meaning that Contentment could still support Umbraco 8. The downsize would be that there would be many #if/#else pre-processor directives littered throughout the codebase.

For more details on this approach, take a read of
the Package Migration to V9 Using Multi-Targeting post on the Umbraco blog.

#if NET
    private readonly ILogger<MyClass> _logger;

    public MyClass(ILogger<MyClass> logger) 
    {
        _logger = logger;
    }
#else
    private readonly ILogger _logger;

    public MyClass(ILogger logger) 
    {
        _logger = logger;
    }
#endif

    public void MyMethod() 
    {
        // Do some common logic and log a result
        var result = "Some value";
#if NET
        _logger.Debug(result);
#else
        _logger.Debug<MyClass>(result);
#endif
    }
Enter fullscreen mode Exit fullscreen mode

Code snippet taken from @mattbrailsford's Adding ILogger<T> support to Umbraco v8 post.

Whilst I really liked the idea of multi-targeting, the amount of pre-processor directives did start to get silly. I wondered why that was and what could be done about it.

Of course, the API between Umbraco 8 and 9 were different, some changes were subtle, others breaking. All for understandable reasons.

With Contentment, one of the more common bits was that the IOHelper.ResolveUrl() was no longer a static method, and a new IIOHelper instance would need to be injected, meaning adding an extra parameter to the class constructor.

Since IIOHelper wasn't available in Umbraco 8, I ended up using conditional pre-processor directives...

#if NET472
    public DropdownListDataListEditor()
    {
    }
#else
    private readonly IIOHelper _ioHelper;
    public DropdownListDataListEditor(IIOHelper ioHelper)
    {
        _ioHelper = ioHelper;
    }
#endif
Enter fullscreen mode Exit fullscreen mode

...and this happened in a lot of places!

My thinking was that I could introduce a polyfill for IIOHelper in Umbraco 8 only. (Given the v8 roadmap, I doubted that it would ever be added to v8.x patch release.) So that's what I did, here's a link to the code for the IIOHelper polyfill and how it is registered using dependency injection in a Composer.

Now my code would look like this...

    private readonly IIOHelper _ioHelper;
    public DropdownListDataListEditor(IIOHelper ioHelper)
    {
        _ioHelper = ioHelper;
    }
Enter fullscreen mode Exit fullscreen mode

Removing the need for the conditional pre-processor directives, and maintaining the same functionality and logic.

Taking this approach to some of the other v9-only interfaces and services, I was able to reduce the verbosity of Contentment's codebase. You can see the other polyfill code on the GitHub repository.


Okay, now what?

This was all great for my Contentment package, happy days. Until when I started developing a new Umbraco package. I developed the code against Umbraco 9, but when I reviewed the code I could see the potential of adding support for Umbraco 8 with a few conditional pre-processor directives. So I copied the polyfill code over from Contentment... wait a minute, what am I doing?

At this point I separated out the polyfill code to its own code library, so that it could be referenced in my other (future) Umbraco packages.

https://github.com/leekelleher/umbraco-polyfill

...and released a NuGet package:
https://www.nuget.org/packages/Our.Umbraco.Community.Polyfill/

Just to note, in it's current release, this library should be considered a continued work-in-progress, and NOT feature complete. If you are a package developer and find there are missing features, I'm happy to collaborate with you on the GitHub repository.

Top comments (0)