Smidge and Umbraco frontends
Tags: umbraco, smidge
Published: 2022-08-17 11:20:00

Previous versions of Umbraco came with the [ClientDependencyFramework](https://github.com/Shazwazza/ClientDependency) that let you bundle styles and scripts across your site. In fact the back office used it heavily to minimise all the Javascript. 

In v9+ this has been replaced by [Smidge](https://github.com/Shazwazza/Smidge) - which does same job for the back office , but out of the box, it isn't quite configured to do the same from your front end (website) files. 

You can add scripts or stylesheets to the site 'bundles' in your razor files: 

for example you can add these to any of your razor templates: 

```
SmidgeHelper.RequiresCss("~/css/site.css");
```
or
```
SmidgeHelper.RequiresJs("~/scripts/payments.js");
```

and then render them in the right place in your HTML with : 

```
@await SmidgeHelper.CssHereAsync();
```
and
```
@await SmidgeHelper.JsHereAsync();
```

this works great but has a few problems : 

1. By default the script files are versioned with a version number that you have to change in the config file or your files will be cached by your site & browser

2. You can't (with these native methods) add extra attributes to the tags (e.g `<script src="file.js" async></script>`)

Fortunately there are some work around for this: 

### 1. Have generated files versioned with a timestamp in dev and appdomain (so after an app restart) on production

There are a few ways to make the css/js be better for developement a) you can set debug to true in the render tags:

```cs
@await SmidgeHelper.CssHereAsync(debug: true)
```

b) you can change the configuration 

now you can do this with a `PostConfigure` method that fires whenever the configuration changes : 

```cs
builder.Services.PostConfigure<SmidgeOptions>(o =>
{
    o.DefaultBundleOptions.ProductionOptions
    .SetCacheBusterType(typeof(TimestampCacheBuster));
});
```

or if you want to be a bit more fancy you can do this based on
the environment that is currently running via a configureOptions interface (where you can inject the Environment)

so in a composer you might have: 
```cs
builder.Services.ConfigureOptions<SmidgeFrontEndSetup>();
```

And then you have a `IConfigureOptions<SmidgeOptions>` interface
to set the value based on if you are running in development.

```cs
public class SmidgeFrontEndSetup : IConfigureOptions<SmidgeOptions>
{
    private readonly IWebHostEnvironment _webHostEnvironment;

    public SmidgeFrontEndSetup(IWebHostEnvironment webHostEnvironment)
    {
        _webHostEnvironment = webHostEnvironment;
    }

    public void Configure(SmidgeOptions options)
    {
        if (_webHostEnvironment.EnvironmentName.Equals("Development", StringComparison.OrdinalIgnoreCase))
        {
            options.DefaultBundleOptions.ProductionOptions
                .SetCacheBusterType(typeof(TimestampCacheBuster));
        }
        else
        {
            options.DefaultBundleOptions.ProductionOptions
                .SetCacheBusterType(typeof(AppDomainLifetimeCacheBuster));
        }
    }
}
```

### 2. Append extra attributes on script and style tags. 

With ClientDependency in v8 you had the ability to append extra attributes to the script or link tags, when you rendered the bundle elements on your page. With the current release of smidge you can't do that with the default helper 

but you can do it with a loop (and yes this could be made into a extension to help you. e.g. 

replace :
```cs
@await SmidgeHelper.JsHereAsync()
```

with: 
```cs
@{
    var urls = await SmidgeHelper.GenerateJsUrlsAsync();
    foreach(var url in urls)
    {
        <script src="@url" async></script>
    }
}
```
---
I think the next step is some of this could be bundled up into helper classes to make it easier, but I think it might be good for the default settings elements to go into the Umbraco.Core and the `SmidgeHelper` methods to go into Smidge then this could work for everyone :smile: