A polyfill for Umbraco packages
Tags: umbraco, polyfill
Published: 2022-04-27 14:29:20

> 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](https://github.com/leekelleher/umbraco-contentment/discussions/105), [Contentment](https://our.umbraco.com/packages/backoffice-extensions/contentment/) to support [Umbraco 9](https://umbraco.com/products/umbraco-cms/umbraco-9/) on ASP.NET Core 5. My initial approach was to drop support for [Umbraco 8](https://umbraco.com/products/umbraco-cms/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](https://github.com/leekelleher/umbraco-contentment/discussions/105#discussioncomment-1547429) 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](https://umbraco.com/blog/multi-targeted-package-migration/) 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
    }
```

> Code snippet taken from @mattbrailsford's [Adding `ILogger<T>` support to Umbraco v8](https://dev.to/mattbrailsford/adding-ilogger-t-support-to-umbraco-v8-5cg8) 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
```

...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](https://github.com/leekelleher/umbraco-contentment/blob/dev/v3.x/src/Umbraco.Community.Contentment/Polyfill/IIOHelper.cs) and [how it is registered using dependency injection in a Composer](https://github.com/leekelleher/umbraco-contentment/blob/dev/v3.x/src/Umbraco.Community.Contentment/Composing/ContentmentComposer.cs#L37).

Now my code would look like this...

```
    private readonly IIOHelper _ioHelper;
    public DropdownListDataListEditor(IIOHelper ioHelper)
    {
        _ioHelper = ioHelper;
    }
```
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](https://github.com/leekelleher/umbraco-contentment/tree/dev/v3.x/src/Umbraco.Community.Contentment/Polyfill).

---

**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](https://github.com/leekelleher/umbraco-polyfill).