Files
Umbraco-CMS/src/Umbraco.Web.Common/RuntimeMinification/SmidgeRuntimeMinifier.cs
Nikolaj Geisle b4fbad14c7 V11: cleanup obsoletes (#12481)
* Remove IExternalLoginService.cs

* Remove UmbracoApplicationComponentsInstallingNotification.cs

* Remove UmbracoApplicationMainDomAcquiredNotification.cs

* Merge IContentTypeWithHistoryCleanup with IContentType.cs

* Remove obsolete ctors from notifications

* Remove obsolete methods

* Remove obsolete method from RequestHandlerSettings.cs

* Fix UmbracoBuilder.Repositories.cs

* RemoveRemove obsolete constants

* Remove obsolete method from IRuntimeMinifier

* Remove SetLastLogin from IMemberRepository

* Revert "RemoveRemove obsolete constants"

This reverts commit cddb8ad1cf3d02bd9949d52bed91b45c8d2d66a9.

* Remove obsoleted Constants-Conventions.cs

* Remove obsolete ctors

* Make ContentData properties immutable

* remove obsolete static property from TestOptionAttributeBase

* Merge IMacroWithAliasService into IMacroService

* Remove IUserComposer

* remove obsolete AddOEmbedProvider method

* remove obsolete static EmbedProvidersCollectionBuilder

* remove obsolete HasFlagAll<T> method

* Remove obsolete LocalizedTextService property from BaseHttpHeaderCheck

* Remove obsolete GetDefaultFIleContent method from ViewHelper

* Remove more obsolete ctors and methods

* Remove obsolete ctor from RelationType

* Remove more obsolete methods

* Remove IExternalLoginRepository

* merge IMacroWithAliasRepository with IMacroRepository

* Remove obsolete methods from ExternalLoginRepository

* Remove obsolete method from IUserRepository

* Remove obsolete SetLastLogin, as it was NoOp

* Remove wierd SetLastLogin method from UserService

* Remove GetLogLevel from ILogViewer

* Remove more obsolete methods and ctors

* Remove more obsoletes

* Use other method in BackOfficeServerVariables.cs since GetAllTypes is now removed

* Remove obsolete ctor

* Remove ConfigureIISServerOptions

* Remove more obsolete methods

* Merge ITwoFactorLoginService2 with ITwoFactorLoginService

* Re-introduce GetCustomGenericProperties in MemberTabsAndPropertiesMapper.cs

Co-authored-by: Nikolaj Geisle <niko737@edu.ucl.dk>
2022-06-07 11:16:30 +02:00

177 lines
7.8 KiB
C#

using Microsoft.Extensions.Options;
using Smidge;
using Smidge.Cache;
using Smidge.CompositeFiles;
using Smidge.FileProcessors;
using Smidge.Models;
using Smidge.Nuglify;
using Smidge.Options;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.WebAssets;
using CssFile = Smidge.Models.CssFile;
using JavaScriptFile = Smidge.Models.JavaScriptFile;
namespace Umbraco.Cms.Web.Common.RuntimeMinification;
public class SmidgeRuntimeMinifier : IRuntimeMinifier
{
private readonly IBundleManager _bundles;
private readonly CacheBusterResolver _cacheBusterResolver;
private readonly Type _cacheBusterType;
private readonly IConfigManipulator _configManipulator;
private readonly Lazy<PreProcessPipeline> _cssMinPipeline;
private readonly Lazy<PreProcessPipeline> _cssNonOptimizedPipeline;
private readonly Lazy<PreProcessPipeline> _cssOptimizedPipeline;
private readonly IHostingEnvironment _hostingEnvironment;
// used only for minifying in MinifyAsync not for an actual pipeline
private readonly Lazy<PreProcessPipeline> _jsMinPipeline;
private readonly Lazy<PreProcessPipeline> _jsNonOptimizedPipeline;
// default pipelines for processing js/css files for the back office
private readonly Lazy<PreProcessPipeline> _jsOptimizedPipeline;
private readonly SmidgeHelperAccessor _smidge;
private ICacheBuster? _cacheBuster;
public SmidgeRuntimeMinifier(
IBundleManager bundles,
SmidgeHelperAccessor smidge,
IHostingEnvironment hostingEnvironment,
IConfigManipulator configManipulator,
IOptions<RuntimeMinificationSettings> runtimeMinificationSettings,
CacheBusterResolver cacheBusterResolver)
{
_bundles = bundles;
_smidge = smidge;
_hostingEnvironment = hostingEnvironment;
_configManipulator = configManipulator;
_cacheBusterResolver = cacheBusterResolver;
_jsMinPipeline = new Lazy<PreProcessPipeline>(() => _bundles.PipelineFactory.Create(typeof(JsMinifier)));
_cssMinPipeline = new Lazy<PreProcessPipeline>(() => _bundles.PipelineFactory.Create(typeof(NuglifyCss)));
// replace the default JsMinifier with NuglifyJs and CssMinifier with NuglifyCss in the default pipelines
// for use with our bundles only (not modifying global options)
_jsOptimizedPipeline = new Lazy<PreProcessPipeline>(() =>
bundles.PipelineFactory.DefaultJs().Replace<JsMinifier, SmidgeNuglifyJs>(_bundles.PipelineFactory));
_jsNonOptimizedPipeline = new Lazy<PreProcessPipeline>(() =>
{
PreProcessPipeline defaultJs = bundles.PipelineFactory.DefaultJs();
// remove minification from this pipeline
defaultJs.Processors.RemoveAll(x => x is JsMinifier);
return defaultJs;
});
_cssOptimizedPipeline = new Lazy<PreProcessPipeline>(() =>
bundles.PipelineFactory.DefaultCss().Replace<CssMinifier, NuglifyCss>(_bundles.PipelineFactory));
_cssNonOptimizedPipeline = new Lazy<PreProcessPipeline>(() =>
{
PreProcessPipeline defaultCss = bundles.PipelineFactory.DefaultCss();
// remove minification from this pipeline
defaultCss.Processors.RemoveAll(x => x is CssMinifier);
return defaultCss;
});
Type cacheBusterType = runtimeMinificationSettings.Value.CacheBuster switch
{
RuntimeMinificationCacheBuster.AppDomain => typeof(AppDomainLifetimeCacheBuster),
RuntimeMinificationCacheBuster.Version => typeof(UmbracoSmidgeConfigCacheBuster),
RuntimeMinificationCacheBuster.Timestamp => typeof(TimestampCacheBuster),
_ => throw new NotImplementedException(),
};
_cacheBusterType = cacheBusterType;
}
public string CacheBuster => (_cacheBuster ??= _cacheBusterResolver.GetCacheBuster(_cacheBusterType)).GetValue();
// only issue with creating bundles like this is that we don't have full control over the bundle options, though that could
public void CreateCssBundle(string bundleName, BundlingOptions bundleOptions, params string[]? filePaths)
{
if (filePaths?.Any(f => !f.StartsWith("/") && !f.StartsWith("~/")) ?? false)
{
throw new InvalidOperationException("All file paths must be absolute");
}
if (_bundles.Exists(bundleName))
{
throw new InvalidOperationException($"The bundle name {bundleName} already exists");
}
PreProcessPipeline pipeline = bundleOptions.OptimizeOutput
? _cssOptimizedPipeline.Value
: _cssNonOptimizedPipeline.Value;
Bundle bundle = _bundles.Create(bundleName, pipeline, WebFileType.Css, filePaths);
bundle.WithEnvironmentOptions(ConfigureBundleEnvironmentOptions(bundleOptions));
}
public async Task<string> RenderCssHereAsync(string bundleName) =>
(await _smidge.SmidgeHelper.CssHereAsync(bundleName, _hostingEnvironment.IsDebugMode)).ToString();
public void CreateJsBundle(string bundleName, BundlingOptions bundleOptions, params string[]? filePaths)
{
if (filePaths?.Any(f => !f.StartsWith("/") && !f.StartsWith("~/")) ?? false)
{
throw new InvalidOperationException("All file paths must be absolute");
}
if (_bundles.Exists(bundleName))
{
throw new InvalidOperationException($"The bundle name {bundleName} already exists");
}
PreProcessPipeline pipeline = bundleOptions.OptimizeOutput
? _jsOptimizedPipeline.Value
: _jsNonOptimizedPipeline.Value;
Bundle bundle = _bundles.Create(bundleName, pipeline, WebFileType.Js, filePaths);
bundle.WithEnvironmentOptions(ConfigureBundleEnvironmentOptions(bundleOptions));
}
public async Task<string> RenderJsHereAsync(string bundleName) =>
(await _smidge.SmidgeHelper.JsHereAsync(bundleName, _hostingEnvironment.IsDebugMode)).ToString();
public async Task<IEnumerable<string>> GetJsAssetPathsAsync(string bundleName) =>
await _smidge.SmidgeHelper.GenerateJsUrlsAsync(bundleName, _hostingEnvironment.IsDebugMode);
public async Task<IEnumerable<string>> GetCssAssetPathsAsync(string bundleName) =>
await _smidge.SmidgeHelper.GenerateCssUrlsAsync(bundleName, _hostingEnvironment.IsDebugMode);
/// <inheritdoc />
public async Task<string> MinifyAsync(string? fileContent, AssetType assetType)
{
switch (assetType)
{
case AssetType.Javascript:
return await _jsMinPipeline.Value
.ProcessAsync(
new FileProcessContext(fileContent, new JavaScriptFile(), BundleContext.CreateEmpty(CacheBuster)));
case AssetType.Css:
return await _cssMinPipeline.Value
.ProcessAsync(new FileProcessContext(fileContent, new CssFile(), BundleContext.CreateEmpty(CacheBuster)));
default:
throw new NotSupportedException("Unexpected AssetType");
}
}
private BundleEnvironmentOptions ConfigureBundleEnvironmentOptions(BundlingOptions bundleOptions)
{
var bundleEnvironmentOptions = new BundleEnvironmentOptions();
// auto-invalidate bundle if files change in debug
bundleEnvironmentOptions.DebugOptions.FileWatchOptions.Enabled = true;
// set cache busters
bundleEnvironmentOptions.DebugOptions.SetCacheBusterType(_cacheBusterType);
bundleEnvironmentOptions.ProductionOptions.SetCacheBusterType(_cacheBusterType);
// config if the files should be combined
bundleEnvironmentOptions.ProductionOptions.ProcessAsCompositeFile = bundleOptions.EnabledCompositeFiles;
return bundleEnvironmentOptions;
}
}