171 lines
7.0 KiB
C#
171 lines
7.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using ClientDependency.Core;
|
|
using ClientDependency.Core.CompositeFiles;
|
|
using ClientDependency.Core.Config;
|
|
using Umbraco.Core.Configuration;
|
|
using Umbraco.Core.IO;
|
|
using Umbraco.Core.Logging;
|
|
using Umbraco.Core.Manifest;
|
|
using Umbraco.Core.PropertyEditors;
|
|
using Umbraco.Core.WebAssets;
|
|
using CssFile = ClientDependency.Core.CssFile;
|
|
using JavascriptFile = ClientDependency.Core.JavascriptFile;
|
|
|
|
namespace Umbraco.Web.WebAssets.CDF
|
|
{
|
|
public class ClientDependencyRuntimeMinifier : IRuntimeMinifier
|
|
{
|
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
private readonly IIOHelper _ioHelper;
|
|
private readonly ILogger _logger;
|
|
private readonly IUmbracoVersion _umbracoVersion;
|
|
|
|
public string CacheBuster => ClientDependencySettings.Instance.Version.ToString();
|
|
|
|
public ClientDependencyRuntimeMinifier(
|
|
IHttpContextAccessor httpContextAccessor,
|
|
IIOHelper ioHelper,
|
|
ILogger logger,
|
|
IUmbracoVersion umbracoVersion)
|
|
{
|
|
_httpContextAccessor = httpContextAccessor;
|
|
_ioHelper = ioHelper;
|
|
_logger = logger;
|
|
_umbracoVersion = umbracoVersion;
|
|
}
|
|
|
|
public void CreateCssBundle(string bundleName, params string[] filePaths)
|
|
{
|
|
if (filePaths.Any(f => !f.StartsWith("/") && !f.StartsWith("~/")))
|
|
throw new InvalidOperationException("All file paths must be absolute");
|
|
|
|
BundleManager.CreateCssBundle(
|
|
bundleName,
|
|
filePaths.Select(x => new CssFile(x)).ToArray());
|
|
}
|
|
|
|
public string RenderCssHere(string bundleName)
|
|
{
|
|
var bundleFiles = GetCssBundleFiles(bundleName);
|
|
if (bundleFiles == null) return string.Empty;
|
|
return RenderOutput(bundleFiles, AssetType.Css);
|
|
}
|
|
|
|
public void CreateJsBundle(string bundleName, params string[] filePaths)
|
|
{
|
|
if (filePaths.Any(f => !f.StartsWith("/") && !f.StartsWith("~/")))
|
|
throw new InvalidOperationException("All file paths must be absolute");
|
|
|
|
BundleManager.CreateJsBundle(
|
|
bundleName,
|
|
filePaths.Select(x => new JavascriptFile(x)).ToArray());
|
|
}
|
|
|
|
public string RenderJsHere(string bundleName)
|
|
{
|
|
var bundleFiles = GetJsBundleFiles(bundleName);
|
|
if (bundleFiles == null) return string.Empty;
|
|
return RenderOutput(bundleFiles, AssetType.Javascript);
|
|
}
|
|
|
|
public Task<IEnumerable<string>> GetAssetPathsAsync(string bundleName)
|
|
{
|
|
var bundleFiles = GetJsBundleFiles(bundleName)?.ToList() ?? GetCssBundleFiles(bundleName)?.ToList();
|
|
if (bundleFiles == null || bundleFiles.Count == 0) return Task.FromResult(Enumerable.Empty<string>());
|
|
|
|
var assetType = bundleFiles[0].DependencyType == ClientDependencyType.Css ? AssetType.Css : AssetType.Javascript;
|
|
|
|
// This is a hack on CDF so that we can resolve CDF urls directly since that isn't directly supported by the lib
|
|
var renderer = ClientDependencySettings.Instance.MvcRendererCollection["Umbraco.DependencyPathRenderer"];
|
|
renderer.RegisterDependencies(bundleFiles, new HashSet<IClientDependencyPath>(), out var scripts, out var stylesheets, _httpContextAccessor.HttpContext);
|
|
|
|
var toParse = assetType == AssetType.Javascript ? scripts : stylesheets;
|
|
return Task.FromResult<IEnumerable<string>>(toParse.Split(new[] { DependencyPathRenderer.Delimiter }, StringSplitOptions.RemoveEmptyEntries));
|
|
}
|
|
|
|
public Task<string> MinifyAsync(string fileContent, AssetType assetType)
|
|
{
|
|
TextReader reader = new StringReader(fileContent);
|
|
|
|
if (assetType == AssetType.Javascript)
|
|
{
|
|
var jsMinifier = new JSMin();
|
|
return Task.FromResult(jsMinifier.Minify(reader));
|
|
}
|
|
|
|
// asset type is Css
|
|
var cssMinifier = new CssMinifier();
|
|
return Task.FromResult(cssMinifier.Minify(reader));
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
// Update ClientDependency version
|
|
var clientDependencyConfig = new ClientDependencyConfiguration(_logger, _ioHelper);
|
|
var clientDependencyUpdated = clientDependencyConfig.UpdateVersionNumber(
|
|
_umbracoVersion.SemanticVersion, DateTime.UtcNow, "yyyyMMdd");
|
|
// Delete ClientDependency temp directories to make sure we get fresh caches
|
|
var clientDependencyTempFilesDeleted = clientDependencyConfig.ClearTempFiles(_httpContextAccessor.HttpContext);
|
|
}
|
|
|
|
private string RenderOutput(IEnumerable<IClientDependencyFile> bundleFiles, AssetType assetType)
|
|
{
|
|
var renderer = ClientDependencySettings.Instance.DefaultMvcRenderer;
|
|
|
|
renderer.RegisterDependencies(
|
|
bundleFiles.ToList(),
|
|
new HashSet<IClientDependencyPath>(),
|
|
out var jsOutput, out var cssOutput, _httpContextAccessor.GetRequiredHttpContext());
|
|
|
|
return assetType == AssetType.Css ? cssOutput : jsOutput;
|
|
}
|
|
|
|
private IEnumerable<IClientDependencyFile> GetCssBundleFiles(string bundleName)
|
|
{
|
|
// internal methods needs reflection
|
|
var bundle = typeof(BundleManager)
|
|
.GetMethod("GetCssBundle", BindingFlags.NonPublic | BindingFlags.Static)
|
|
.Invoke(null, new object[] { bundleName });
|
|
var bundleFiles = (IEnumerable<IClientDependencyFile>) bundle?.GetType().GetProperty("Files").GetValue(bundle, null);
|
|
return bundleFiles;
|
|
}
|
|
|
|
private IEnumerable<IClientDependencyFile> GetJsBundleFiles(string bundleName)
|
|
{
|
|
// internal methods needs reflection
|
|
var bundle = typeof(BundleManager)
|
|
.GetMethod("GetJsBundle", BindingFlags.NonPublic | BindingFlags.Static)
|
|
.Invoke(null, new object[] { bundleName });
|
|
var bundleFiles = (IEnumerable<IClientDependencyFile>)bundle?.GetType().GetProperty("Files").GetValue(bundle, null);
|
|
return bundleFiles;
|
|
}
|
|
|
|
private ClientDependencyType MapDependencyTypeValue(AssetType type)
|
|
{
|
|
return type switch
|
|
{
|
|
AssetType.Javascript => ClientDependencyType.Javascript,
|
|
AssetType.Css => ClientDependencyType.Css,
|
|
_ => (ClientDependencyType) Enum.Parse(typeof(ClientDependencyType), type.ToString(), true)
|
|
};
|
|
}
|
|
|
|
private IClientDependencyFile MapAssetFile(IAssetFile assetFile)
|
|
{
|
|
var assetFileType = (AssetFile)assetFile;
|
|
var basicFile = new BasicFile(MapDependencyTypeValue(assetFileType.DependencyType))
|
|
{
|
|
FilePath = assetFile.FilePath
|
|
};
|
|
|
|
return basicFile;
|
|
}
|
|
}
|
|
}
|