AB#8522 - Smidge implementation of the Runtime Minifier

This commit is contained in:
Bjarke Berg
2020-03-30 21:27:35 +02:00
parent 219391246d
commit ffc6ce6553
45 changed files with 586 additions and 404 deletions
@@ -22,6 +22,6 @@ namespace Umbraco.Configuration.Models
/// Gets a value indicating whether umbraco is running in [debug mode].
/// </summary>
/// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
public bool DebugMode => _configuration.GetValue(Prefix+":Debug", false);
public bool DebugMode => _configuration.GetValue(Prefix+"Debug", false);
}
}
+73
View File
@@ -1,6 +1,13 @@
using Umbraco.Core.Composing;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.Actions;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Dashboards;
using Umbraco.Web.Editors;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Routing;
using Umbraco.Web.Sections;
using Umbraco.Web.Tour;
namespace Umbraco.Core
{
@@ -9,6 +16,72 @@ namespace Umbraco.Core
#region Collection Builders
/// <summary>
/// Gets the actions collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
internal static ActionCollectionBuilder Actions(this Composition composition)
=> composition.WithCollectionBuilder<ActionCollectionBuilder>();
/// <summary>
/// Gets the content apps collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
public static ContentAppFactoryCollectionBuilder ContentApps(this Composition composition)
=> composition.WithCollectionBuilder<ContentAppFactoryCollectionBuilder>();
/// <summary>
/// Gets the content finders collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
public static ContentFinderCollectionBuilder ContentFinders(this Composition composition)
=> composition.WithCollectionBuilder<ContentFinderCollectionBuilder>();
/// <summary>
/// Gets the editor validators collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
internal static EditorValidatorCollectionBuilder EditorValidators(this Composition composition)
=> composition.WithCollectionBuilder<EditorValidatorCollectionBuilder>();
/// <summary>
/// Gets the health checks collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static HealthCheckCollectionBuilder HealthChecks(this Composition composition)
=> composition.WithCollectionBuilder<HealthCheckCollectionBuilder>();
/// <summary>
/// Gets the TourFilters collection builder.
/// </summary>
public static TourFilterCollectionBuilder TourFilters(this Composition composition)
=> composition.WithCollectionBuilder<TourFilterCollectionBuilder>();
/// <summary>
/// Gets the url providers collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static UrlProviderCollectionBuilder UrlProviders(this Composition composition)
=> composition.WithCollectionBuilder<UrlProviderCollectionBuilder>();
/// <summary>
/// Gets the media url providers collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this Composition composition)
=> composition.WithCollectionBuilder<MediaUrlProviderCollectionBuilder>();
/// <summary>
/// Gets the backoffice sections/applications collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static SectionCollectionBuilder Sections(this Composition composition)
=> composition.WithCollectionBuilder<SectionCollectionBuilder>();
/// <summary>
/// Gets the components collection builder.
/// </summary>
@@ -5,7 +5,7 @@ namespace Umbraco.Web
/// <summary>
/// Implements a hybrid <see cref="IUmbracoContextAccessor"/>.
/// </summary>
internal class HybridUmbracoContextAccessor : HybridAccessorBase<IUmbracoContext>, IUmbracoContextAccessor
public class HybridUmbracoContextAccessor : HybridAccessorBase<IUmbracoContext>, IUmbracoContextAccessor
{
/// <summary>
/// Initializes a new instance of the <see cref="HybridUmbracoContextAccessor"/> class.
+8 -9
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Web;
using System.Collections.Generic;
using System.Threading.Tasks;
using Umbraco.Core.Assets;
namespace Umbraco.Core.Runtime
@@ -10,23 +9,23 @@ namespace Umbraco.Core.Runtime
string GetHashValue { get; }
//return type HtmlHelper
void RequiresCss(string filePath, string bundleName);
void RequiresCss(string bundleName, params string[] filePaths);
//return type IHtmlString
//IClientDependencyPath[]
string RenderCssHere(string bundleName);
// return type HtmlHelper
void RequiresJs(string filePath, string bundleName);
void RequiresJs(string bundleName, params string[] filePaths);
// return type IHtmlString
string RenderJsHere(string bundleName);
IEnumerable<string> GetAssetPaths(AssetType assetType, List<IAssetFile> attributes);
Task<IEnumerable<string>> GetAssetPathsAsync(AssetType assetType, List<IAssetFile> attributes);
string Minify(string src, AssetType assetType);
Task<string> MinifyAsync(string fileContent, AssetType assetType);
void Reset();
string GetScriptForBackOffice();
IEnumerable<string> GetAssetList();
Task<string> GetScriptForBackOfficeAsync();
Task<IEnumerable<string>> GetAssetListAsync();
}
}
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
namespace Umbraco.Web.Models
{
public class ImageProcessorImageUrlGenerator : IImageUrlGenerator
public class ImageSharpImageUrlGenerator : IImageUrlGenerator
{
public string GetImageUrl(ImageUrlGenerationOptions options)
{
@@ -1,34 +1,34 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Assets;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Runtime;
using Umbraco.Web.Composing;
using Umbraco.Web.PropertyEditors;
namespace Umbraco.Web.JavaScript
{
internal abstract class AssetInitialization
public abstract class AssetInitialization
{
private readonly IRuntimeMinifier _runtimeMinifier;
private readonly PropertyEditorCollection _propertyEditorCollection;
public AssetInitialization(IRuntimeMinifier runtimeMinifier)
public AssetInitialization(IRuntimeMinifier runtimeMinifier, PropertyEditorCollection propertyEditorCollection)
{
_runtimeMinifier = runtimeMinifier;
_propertyEditorCollection = propertyEditorCollection;
}
protected IEnumerable<string> ScanPropertyEditors(AssetType assetType, HttpContextBase httpContext)
protected async Task<IEnumerable<string>> ScanPropertyEditorsAsync(AssetType assetType)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
var attributes = Current.PropertyEditors
var attributes = _propertyEditorCollection
.SelectMany(x => x.GetType().GetCustomAttributes<PropertyEditorAssetAttribute>(false))
.Where(x => x.AssetType == assetType)
.Select(x => x.DependencyFile)
.ToList();
return _runtimeMinifier.GetAssetPaths(assetType, attributes);
return await _runtimeMinifier.GetAssetPathsAsync(assetType, attributes);
}
}
}
@@ -2,19 +2,25 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Umbraco.Core.Assets;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Runtime;
namespace Umbraco.Web.JavaScript
{
internal class CssInitialization : AssetInitialization
public class CssInitialization : AssetInitialization
{
private readonly IManifestParser _parser;
private readonly IRuntimeMinifier _runtimeMinifier;
public CssInitialization(IManifestParser parser, IRuntimeMinifier runtimeMinifier) : base(runtimeMinifier)
public CssInitialization(
IManifestParser parser,
IRuntimeMinifier runtimeMinifier,
PropertyEditorCollection propertyEditorCollection)
: base(runtimeMinifier, propertyEditorCollection)
{
_parser = parser;
_runtimeMinifier = runtimeMinifier;
@@ -23,20 +29,20 @@ namespace Umbraco.Web.JavaScript
/// <summary>
/// Processes all found manifest files, and outputs css inject calls for all css files found in all manifests.
/// </summary>
public string GetStylesheetInitialization(HttpContextBase httpContext)
public async Task<string> GetStylesheetInitializationAsync(Uri requestUrl)
{
var files = GetStylesheetFiles(httpContext);
var files = await GetStylesheetFilesAsync(requestUrl);
return WriteScript(files);
}
public IEnumerable<string> GetStylesheetFiles(HttpContextBase httpContext)
public async Task<IEnumerable<string>> GetStylesheetFilesAsync(Uri requestUrl)
{
var stylesheets = new HashSet<string>();
var optimizedManifest = JavaScriptHelper.OptimizeAssetCollection(_parser.Manifest.Stylesheets, AssetType.Css, httpContext, _runtimeMinifier);
var optimizedManifest = await JavaScriptHelper.OptimizeAssetCollectionAsync(_parser.Manifest.Stylesheets, AssetType.Css, requestUrl, _runtimeMinifier);
foreach (var stylesheet in optimizedManifest)
stylesheets.Add(stylesheet);
foreach (var stylesheet in ScanPropertyEditors(AssetType.Css, httpContext))
foreach (var stylesheet in await ScanPropertyEditorsAsync(AssetType.Css))
stylesheets.Add(stylesheet);
return stylesheets.ToArray();
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
@@ -11,6 +11,7 @@ using Umbraco.Core.Assets;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Runtime;
using Umbraco.Infrastructure.RuntimeMinification;
namespace Umbraco.Web.JavaScript
{
@@ -28,13 +29,12 @@ namespace Umbraco.Web.JavaScript
/// <summary>
/// Gets the JS initialization script to boot the back office application
/// </summary>
/// <param name="httpContext"></param>
/// <param name="scripts"></param>
/// <param name="angularModule">
/// The angular module name to boot
/// </param>
/// <returns></returns>
public static string GetJavascriptInitialization(HttpContextBase httpContext, IEnumerable<string> scripts, string angularModule, IGlobalSettings globalSettings, IIOHelper ioHelper)
public static string GetJavascriptInitialization(IEnumerable<string> scripts, string angularModule, IGlobalSettings globalSettings, IIOHelper ioHelper)
{
var jarray = new StringBuilder();
jarray.AppendLine("[");
@@ -80,9 +80,9 @@ namespace Umbraco.Web.JavaScript
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
}
internal static IEnumerable<string> OptimizeTinyMceScriptFiles(HttpContextBase httpContext, IRuntimeMinifier runtimeMinifier)
public static async Task<IEnumerable<string>> OptimizeTinyMceScriptFilesAsync(Uri requestUrl, IRuntimeMinifier runtimeMinifier)
{
return OptimizeScriptFiles(httpContext, GetTinyMceInitialization(), runtimeMinifier);
return await OptimizeScriptFilesAsync(requestUrl, GetTinyMceInitialization(), runtimeMinifier);
}
@@ -90,7 +90,7 @@ namespace Umbraco.Web.JavaScript
/// Returns the default config as a JArray
/// </summary>
/// <returns></returns>
internal static IEnumerable<string> GetPreviewInitialization()
public static IEnumerable<string> GetPreviewInitialization()
{
var resources = JsonConvert.DeserializeObject<JArray>(Resources.PreviewInitialize);
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
@@ -100,30 +100,27 @@ namespace Umbraco.Web.JavaScript
/// <summary>
/// Returns a list of optimized script paths
/// </summary>
/// <param name="httpContext"></param>
/// <param name="requestUrl"></param>
/// <param name="scriptFiles"></param>
/// <param name="runtimeMinifier"></param>
/// <returns></returns>
/// <remarks>
/// Used to cache bust and optimize script paths
/// </remarks>
public static IEnumerable<string> OptimizeScriptFiles(HttpContextBase httpContext, IEnumerable<string> scriptFiles, IRuntimeMinifier runtimeMinifier)
public static async Task<IEnumerable<string>> OptimizeScriptFilesAsync(Uri requestUrl, IEnumerable<string> scriptFiles, IRuntimeMinifier runtimeMinifier)
{
var scripts = new HashSet<string>();
foreach (var script in scriptFiles)
scripts.Add(script);
scripts = new HashSet<string>(OptimizeAssetCollection(scripts, AssetType.Javascript, httpContext, runtimeMinifier));
scripts = new HashSet<string>(await OptimizeAssetCollectionAsync(scripts, AssetType.Javascript, requestUrl, runtimeMinifier));
return scripts.ToArray();
}
internal static IEnumerable<string> OptimizeAssetCollection(IEnumerable<string> assets, AssetType assetType, HttpContextBase httpContext, IRuntimeMinifier runtimeMinifier)
internal static async Task<IEnumerable<string>> OptimizeAssetCollectionAsync(IEnumerable<string> assets, AssetType assetType, Uri requestUrl, IRuntimeMinifier runtimeMinifier)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
var requestUrl = httpContext.Request.Url;
if (requestUrl == null) throw new ArgumentException("HttpContext.Request.Url is null.", nameof(httpContext));
if (requestUrl == null) throw new ArgumentNullException(nameof(requestUrl));
var dependencies = assets.Where(x => x.IsNullOrWhiteSpace() == false).Select(x =>
{
@@ -140,7 +137,7 @@ namespace Umbraco.Web.JavaScript
}).ToList();
return runtimeMinifier.GetAssetPaths(assetType, dependencies);;
return await runtimeMinifier.GetAssetPathsAsync(assetType, dependencies);
}
}
}
@@ -1,11 +1,14 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Assets;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Runtime;
using Umbraco.Infrastructure.RuntimeMinification;
namespace Umbraco.Web.JavaScript
{
@@ -13,12 +16,12 @@ namespace Umbraco.Web.JavaScript
/// Reads from all defined manifests and ensures that any of their initialization is output with the
/// main Umbraco initialization output.
/// </summary>
internal class JsInitialization : AssetInitialization
public class JsInitialization : AssetInitialization
{
private readonly IManifestParser _parser;
private readonly IRuntimeMinifier _runtimeMinifier;
public JsInitialization(IManifestParser parser, IRuntimeMinifier runtimeMinifier) : base(runtimeMinifier)
public JsInitialization(IManifestParser parser, IRuntimeMinifier runtimeMinifier, PropertyEditorCollection propertyEditorCollection) : base(runtimeMinifier, propertyEditorCollection)
{
_parser = parser;
_runtimeMinifier = runtimeMinifier;
@@ -27,7 +30,7 @@ namespace Umbraco.Web.JavaScript
/// <summary>
/// Returns a list of optimized script paths for the back office
/// </summary>
/// <param name="httpContext"></param>
/// <param name="requestUrl"></param>
/// <param name="umbracoInit"></param>
/// <param name="additionalJsFiles"></param>
/// <returns>
@@ -36,7 +39,7 @@ namespace Umbraco.Web.JavaScript
/// <remarks>
/// Used to cache bust and optimize script paths for the back office
/// </remarks>
public IEnumerable<string> OptimizeBackOfficeScriptFiles(HttpContextBase httpContext, IEnumerable<string> umbracoInit, IEnumerable<string> additionalJsFiles = null)
public async Task<IEnumerable<string>> OptimizeBackOfficeScriptFilesAsync(Uri requestUrl, IEnumerable<string> umbracoInit, IEnumerable<string> additionalJsFiles = null)
{
var scripts = new HashSet<string>();
foreach (var script in umbracoInit)
@@ -47,9 +50,9 @@ namespace Umbraco.Web.JavaScript
foreach (var script in additionalJsFiles)
scripts.Add(script);
scripts = new HashSet<string>(JavaScriptHelper.OptimizeAssetCollection(scripts, AssetType.Javascript, httpContext, _runtimeMinifier));
scripts = new HashSet<string>(await JavaScriptHelper.OptimizeAssetCollectionAsync(scripts, AssetType.Javascript, requestUrl, _runtimeMinifier));
foreach (var script in ScanPropertyEditors(AssetType.Javascript, httpContext))
foreach (var script in await ScanPropertyEditorsAsync(AssetType.Javascript))
scripts.Add(script);
return scripts.ToArray();
@@ -59,7 +62,7 @@ namespace Umbraco.Web.JavaScript
/// Returns the default config as a JArray
/// </summary>
/// <returns></returns>
internal static IEnumerable<string> GetDefaultInitialization()
public static IEnumerable<string> GetDefaultInitialization()
{
var resources = JsonConvert.DeserializeObject<JArray>(Resources.JsInitialize);
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
@@ -8,7 +8,7 @@
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Web.JavaScript {
namespace Umbraco.Infrastructure.RuntimeMinification {
using System;
@@ -19,7 +19,7 @@ namespace Umbraco.Web.JavaScript {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
@@ -39,7 +39,7 @@ namespace Umbraco.Web.JavaScript {
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Web.JavaScript.Resources", typeof(Resources).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Infrastructure.RuntimeMinification.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
@@ -76,9 +76,9 @@ namespace Umbraco.Web.JavaScript {
///
/// &apos;lib/angular-route/angular-route.js&apos;,
/// &apos;lib/angular-cookies/angular-cookies.js&apos;,
/// &apos;lib/angular-aria/angular-aria.min.js&apos;,
/// &apos;lib/angular-touch/angular-touch.js&apos;,
/// &apos;lib/angular-sanitize/angular-sanitize.js&apos;,
/// &apos;lib/an [rest of string was truncated]&quot;;.
/// &apos;lib/angula [rest of string was truncated]&quot;;.
/// </summary>
internal static string JsInitialize {
get {
@@ -149,9 +149,18 @@ namespace Umbraco.Web.JavaScript {
/// <summary>
/// Looks up a localized string similar to [
/// &apos;../lib/tinymce/tinymce.min.js&apos;,
///]
///.
/// &apos;lib/tinymce/tinymce.min.js&apos;,
///
/// &apos;lib/tinymce/plugins/paste/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/anchor/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/charmap/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/table/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/lists/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/advlist/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/hr/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/autolink/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/directionality/plugin.min.js&apos;,
/// &apos;lib/tinymce/plugins/t [rest of string was truncated]&quot;;.
/// </summary>
internal static string TinyMceInitialize {
get {
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="JsInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>jsinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Main" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Main.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="PreviewInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>previewinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="ServerVariables" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>servervariables.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TinyMceInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>TinyMceInitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Umbraco.Infrastructure.RuntimeMinification;
namespace Umbraco.Web.JavaScript
{
@@ -13,7 +14,7 @@ namespace Umbraco.Web.JavaScript
internal const string Token = "##Variables##";
internal static string Parse(Dictionary<string, object> items)
public static string Parse(Dictionary<string, object> items)
{
var vars = Resources.ServerVariables;
@@ -43,10 +43,23 @@
<ItemGroup>
<Compile Remove="obj\**" />
<Compile Update="RuntimeMinification\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources2.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="obj\**" />
<EmbeddedResource Include="RuntimeMinification\JsInitialize.js" />
<EmbeddedResource Include="RuntimeMinification\Main.js" />
<EmbeddedResource Include="RuntimeMinification\PreviewInitialize.js" />
<EmbeddedResource Include="RuntimeMinification\ServerVariables.js" />
<EmbeddedResource Update="RuntimeMinification\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
@@ -30,7 +30,7 @@ namespace Umbraco.Tests.Models
private static readonly ImageUrlGenerationOptions.CropCoordinates Crop = new ImageUrlGenerationOptions.CropCoordinates(0.58729977382575338m, 0.055768992440203169m, 0m, 0.32457553600198386m);
private static readonly ImageUrlGenerationOptions.FocalPointPosition Focus1 = new ImageUrlGenerationOptions.FocalPointPosition(0.80827067669172936m, 0.96m);
private static readonly ImageUrlGenerationOptions.FocalPointPosition Focus2 = new ImageUrlGenerationOptions.FocalPointPosition(0.41m, 0.4275m);
private static readonly ImageProcessorImageUrlGenerator Generator = new ImageProcessorImageUrlGenerator();
private static readonly ImageSharpImageUrlGenerator Generator = new ImageSharpImageUrlGenerator();
[Test]
public void GetCropUrl_CropAliasTest()
@@ -2,8 +2,16 @@ using Microsoft.AspNetCore.Http;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Hosting;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Net;
using Umbraco.Core.Runtime;
using Umbraco.Core.Security;
using Umbraco.Web.Models;
using Umbraco.Web.Models.PublishedContent;
using Umbraco.Web.PropertyEditors;
using Umbraco.Web.Routing;
using Umbraco.Web.Templates;
namespace Umbraco.Web.BackOffice.AspNetCore
{
@@ -22,6 +30,37 @@ namespace Umbraco.Web.BackOffice.AspNetCore
// Our own netcore implementations
composition.RegisterUnique<IUmbracoApplicationLifetime, AspNetCoreUmbracoApplicationLifetime>();
composition.RegisterUnique<IApplicationShutdownRegistry, AspNetCoreApplicationShutdownRegistry>();
composition.RegisterUnique<IPasswordHasher, AspNetCorePasswordHasher>();
// register the http context and umbraco context accessors
// we *should* use the HttpContextUmbracoContextAccessor, however there are cases when
// we have no http context, eg when booting Umbraco or in background threads, so instead
// let's use an hybrid accessor that can fall back to a ThreadStatic context.
composition.RegisterUnique<IUmbracoContextAccessor, HybridUmbracoContextAccessor>();
// register the umbraco context factory
// composition.RegisterUnique<IUmbracoContextFactory, UmbracoContextFactory>();
composition.RegisterUnique<IPublishedUrlProvider, UrlProvider>();
composition.RegisterUnique<HtmlLocalLinkParser>();
composition.RegisterUnique<HtmlImageSourceParser>();
composition.RegisterUnique<HtmlUrlParser>();
composition.RegisterUnique<RichTextEditorPastedImages>();
composition.UrlProviders()
.Append<AliasUrlProvider>()
.Append<DefaultUrlProvider>();
composition.MediaUrlProviders()
.Append<DefaultMediaUrlProvider>();
composition.RegisterUnique<ISiteDomainHelper, SiteDomainHelper>();
// register properties fallback
composition.RegisterUnique<IPublishedValueFallback, PublishedValueFallback>();
composition.RegisterUnique<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
}
}
}
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Identity;
using IPasswordHasher = Umbraco.Core.Security.IPasswordHasher;
namespace Umbraco.Web.BackOffice.AspNetCore
{
public class AspNetCorePasswordHasher : IPasswordHasher
{
private PasswordHasher<object> _underlyingHasher;
public AspNetCorePasswordHasher()
{
_underlyingHasher = new PasswordHasher<object>();
}
public string HashPassword(string password)
{
return _underlyingHasher.HashPassword(null, password);
}
}
}
@@ -9,6 +9,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Smidge;
using Smidge.Nuglify;
using Umbraco.Composing;
using Umbraco.Configuration;
using Umbraco.Core;
@@ -166,6 +167,7 @@ namespace Umbraco.Web.BackOffice.AspNetCore
IConfiguration configuration)
{
services.AddSmidge(configuration.GetSection(Constants.Configuration.ConfigPrefix+"RuntimeMinification"));
services.AddSmidgeNuglify();
return services;
}
@@ -0,0 +1,18 @@
using System;
using Microsoft.AspNetCore.Builder;
using Smidge;
namespace Umbraco.Web.Common.AspNetCore
{
public static class UmbracoRuntimeMinificationApplicationBuilderExtensions
{
public static IApplicationBuilder UseUmbracoRuntimeMinification(this IApplicationBuilder app)
{
if (app == null) throw new ArgumentNullException(nameof(app));
app.UseSmidge();
return app;
}
}
}
@@ -0,0 +1,44 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Core.Runtime;
using Umbraco.Web.BackOffice.Filters;
namespace Umbraco.Web.BackOffice.Controllers
{
public class BackOfficeController : Controller
{
private readonly IRuntimeMinifier _runtimeMinifier;
public BackOfficeController(IRuntimeMinifier runtimeMinifier)
{
_runtimeMinifier = runtimeMinifier;
}
// GET
public IActionResult Index()
{
return View();
}
/// <summary>
/// Returns the JavaScript main file including all references found in manifests
/// </summary>
/// <returns></returns>
[MinifyJavaScriptResult(Order = 0)]
public async Task<IActionResult> Application()
{
var result = await _runtimeMinifier.GetScriptForBackOfficeAsync();
return new JavaScriptResult(result);
}
}
public class JavaScriptResult : ContentResult
{
public JavaScriptResult(string script)
{
this.Content = script;
this.ContentType = "application/javascript";
}
}
}
@@ -0,0 +1,52 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using Umbraco.Core.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Core.Assets;
using Umbraco.Core.Runtime;
using Umbraco.Web.BackOffice.Controllers;
namespace Umbraco.Web.BackOffice.Filters
{
public class MinifyJavaScriptResult : ActionFilterAttribute
{
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// logic before action goes here
var hostingEnvironment = context.HttpContext.RequestServices.GetService<IHostingEnvironment>();
if (!hostingEnvironment.IsDebugMode)
{
var runtimeMinifier = context.HttpContext.RequestServices.GetService<IRuntimeMinifier>();
if (context.Result is JavaScriptResult jsResult)
{
var result = jsResult.Content;
var minified = await runtimeMinifier.MinifyAsync(result, AssetType.Javascript);
jsResult.Content = minified;
}
}
await next(); // the actual action
// logic after the action goes here
}
public override void OnResultExecuting(ResultExecutingContext context)
{
base.OnResultExecuting(context);
//minify the result
}
}
}
@@ -8,12 +8,12 @@ namespace Umbraco.Web.BackOffice.Smidge
{
public void Initialize()
{
throw new NotImplementedException();
}
public void Terminate()
{
throw new NotImplementedException();
}
}
}
@@ -7,12 +7,11 @@ using Umbraco.Core.Runtime;
namespace Umbraco.Web.BackOffice.Smidge
{
public sealed class SmidgeComposer : ComponentComposer<SmidgeComponent>
public sealed class SmidgeComposer : IComposer
{
public override void Compose(Composition composition)
public void Compose(Composition composition)
{
base.Compose(composition);
composition.RegisterUnique<IRuntimeMinifier, SmidgeRuntimeMinifier>();
composition.Register<IRuntimeMinifier, SmidgeRuntimeMinifier>(Lifetime.Scope);
}
}
}
@@ -1,92 +1,145 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Configuration;
using Smidge;
using Smidge.Cache;
using Smidge.CompositeFiles;
using Smidge.FileProcessors;
using Smidge.Nuglify;
using Smidge.Models;
using Umbraco.Core;
using Umbraco.Core.Assets;
using Umbraco.Core.Configuration;
using Umbraco.Core.Hosting;
using Umbraco.Core.IO;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Runtime;
using Umbraco.Web.JavaScript;
using CssFile = Smidge.Models.CssFile;
using JavaScriptFile = Smidge.Models.JavaScriptFile;
namespace Umbraco.Web.BackOffice.Smidge
{
public class SmidgeRuntimeMinifier : IRuntimeMinifier
{
private readonly IGlobalSettings _globalSettings;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IIOHelper _ioHelper;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ISmidgeConfig _smidgeConfig;
private readonly IManifestParser _manifestParser;
private readonly PreProcessPipelineFactory _preProcessPipelineFactory;
private readonly PropertyEditorCollection _propertyEditorCollection;
private readonly SmidgeHelper _smidge;
// TODO: We need to use IConfiguration to get the section (ConfigurationManager is not the way to do it)
public string GetHashValue => new SmidgeConfig((IConfiguration)ConfigurationManager.GetSection("Umbraco:Smidge")).Version;
private PreProcessPipeline _jsPipeline;
private PreProcessPipeline _cssPipeline;
public SmidgeRuntimeMinifier(SmidgeHelper smidge)
public SmidgeRuntimeMinifier(
SmidgeHelper smidge,
PreProcessPipelineFactory preProcessPipelineFactory,
IManifestParser manifestParser,
IHttpContextAccessor httpContextAccessor,
PropertyEditorCollection propertyEditorCollection,
IGlobalSettings globalSettings,
IIOHelper ioHelper,
IHostingEnvironment hostingEnvironment,
ISmidgeConfig smidgeConfig)
{
_smidge = smidge;
}
public void RequiresCss(string filePath, string bundleName)
{
throw new NotImplementedException();
_preProcessPipelineFactory = preProcessPipelineFactory;
_manifestParser = manifestParser;
_httpContextAccessor = httpContextAccessor;
_propertyEditorCollection = propertyEditorCollection;
_globalSettings = globalSettings;
_ioHelper = ioHelper;
_hostingEnvironment = hostingEnvironment;
_smidgeConfig = smidgeConfig;
}
public string RenderCssHere(string bundleName)
private PreProcessPipeline JsPipeline => _jsPipeline ??= _preProcessPipelineFactory.Create(typeof(JsMinifier));
private PreProcessPipeline CssPipeline => _cssPipeline ??= _preProcessPipelineFactory.Create(typeof(NuglifyCss));
private Uri GetRequestUrl() => new Uri(_httpContextAccessor.HttpContext.Request.GetEncodedUrl(), UriKind.Absolute);
public string GetHashValue => _smidgeConfig.Version;
public void RequiresCss(string bundleName, params string[] filePaths) => _smidge.CreateCssBundle(bundleName).RequiresCss(filePaths);
public string RenderCssHere(string bundleName) => _smidge.CssHereAsync(bundleName).ToString();
public void RequiresJs(string bundleName, params string[] filePaths) => _smidge.CreateJsBundle(bundleName).RequiresJs(filePaths);
public string RenderJsHere(string bundleName) => _smidge.JsHereAsync(bundleName).ToString();
public async Task<IEnumerable<string>> GetAssetPathsAsync(AssetType assetType, List<IAssetFile> attributes)
{
return _smidge.CssHereAsync(bundleName).ToString();
}
public void RequiresJs(string filePath, string bundleName)
{
throw new NotImplementedException();
}
var files = attributes
.Where(x => x.DependencyType == assetType)
.Select(x=>x.FilePath)
.ToArray();
public string RenderJsHere(string bundleName)
{
return _smidge.JsHereAsync(bundleName).ToString();
}
if (files.Length == 0) return Array.Empty<string>();
public IEnumerable<string> GetAssetPaths(AssetType assetType, List<IAssetFile> attributes)
{
var parsed = new List<string>();
if (assetType == AssetType.Javascript)
attributes.ForEach(x => parsed.AddRange(_smidge.GenerateJsUrlsAsync(x.Bundle).Result));
else
attributes.ForEach(x => parsed.AddRange(_smidge.GenerateCssUrlsAsync(x.Bundle).Result));
return parsed;
}
public string Minify(string src, AssetType assetType)
{
if (assetType == AssetType.Javascript)
{
_smidge.RequiresJs(files);
// TODO: use NuglifyJs to minify JS files (https://github.com/Shazwazza/Smidge/blob/master/src/Smidge.Nuglify/NuglifyJs.cs)
return await _smidge.GenerateJsUrlsAsync(JsPipeline, _hostingEnvironment.IsDebugMode);
}
else
{
// TODO: use NuglifyCss to minify CSS files (https://github.com/Shazwazza/Smidge/blob/master/src/Smidge.Nuglify/NuglifyCss.cs)
}
_smidge.RequiresCss(files);
throw new NotImplementedException();
return await _smidge.GenerateJsUrlsAsync(CssPipeline, _hostingEnvironment.IsDebugMode);
}
}
public async Task<string> MinifyAsync(string fileContent, AssetType assetType)
{
if (assetType == AssetType.Javascript)
{
return await JsPipeline
.ProcessAsync(
new FileProcessContext(fileContent, new JavaScriptFile(), BundleContext.CreateEmpty()));
}
else
{
return await CssPipeline
.ProcessAsync(new FileProcessContext(fileContent, new CssFile(), BundleContext.CreateEmpty()));
}
}
public void Reset()
{
// TODO: Need to figure out how to delete temp directories to make sure we get fresh caches
throw new NotImplementedException();
}
public string GetScriptForBackOffice()
public async Task<string> GetScriptForBackOfficeAsync()
{
throw new NotImplementedException();
var initJs = new JsInitialization(_manifestParser, this, _propertyEditorCollection);
var initCss = new CssInitialization(_manifestParser, this, _propertyEditorCollection);
var requestUrl = GetRequestUrl();
var files = await initJs.OptimizeBackOfficeScriptFilesAsync(requestUrl, JsInitialization.GetDefaultInitialization());
var result = JavaScriptHelper.GetJavascriptInitialization(files, "umbraco", _globalSettings, _ioHelper);
result += await initCss.GetStylesheetInitializationAsync(requestUrl);
return result;
}
public IEnumerable<string> GetAssetList()
public async Task<IEnumerable<string>> GetAssetListAsync()
{
throw new NotImplementedException();
var initJs = new JsInitialization(_manifestParser, this, _propertyEditorCollection);
var initCss = new CssInitialization(_manifestParser, this, _propertyEditorCollection);
var assets = new List<string>();
var requestUrl = GetRequestUrl();
assets.AddRange(await initJs.OptimizeBackOfficeScriptFilesAsync(requestUrl, Enumerable.Empty<string>()));
assets.AddRange(await initCss.GetStylesheetFilesAsync(requestUrl));
return assets;
}
}
}
+2
View File
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Umbraco.Core.Composing;
namespace Umbraco.Web.UI.BackOffice
+14 -2
View File
@@ -8,7 +8,9 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Smidge;
using Umbraco.Web.BackOffice.AspNetCore;
using Umbraco.Web.Common.AspNetCore;
using Umbraco.Web.Website.AspNetCore;
@@ -41,6 +43,8 @@ namespace Umbraco.Web.UI.BackOffice
services.AddUmbracoRuntimeMinifier(_config);
services.AddUmbracoCore(_webHostEnvironment);
services.AddUmbracoWebsite();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -50,14 +54,22 @@ namespace Umbraco.Web.UI.BackOffice
{
app.UseDeveloperExceptionPage();
}
app.Use(async (context, next) =>
{
await next();
});
app.UseUmbracoWebsite();
app.UseUmbracoBackOffice();
app.UseRouting();
app.UseUmbracoRuntimeMinification();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute("Backoffice", "/umbraco/{Action}", new
{
Controller = "BackOffice",
Action = "Default"
});
endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); });
});
}
@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>Umbraco.Web.UI.BackOffice</RootNamespace>
<RootNamespace>Umbraco.Web.UI.NetCore</RootNamespace>
</PropertyGroup>
<ItemGroup>
@@ -15,8 +15,23 @@
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\~\App_Data\TEMP\TypesCache\umbraco-types.DESKTOP-2016.hash" />
<_ContentIncludedByDefault Remove="wwwroot\~\App_Data\TEMP\TypesCache\umbraco-types.DESKTOP-2016.list" />
<Compile Remove="Umbraco\**" />
<Compile Remove="wwwroot\Umbraco\**" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Remove="Umbraco\**" />
<EmbeddedResource Remove="wwwroot\Umbraco\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Umbraco\**" />
<None Remove="wwwroot\Umbraco\**" />
</ItemGroup>
<ItemGroup>
<Content Remove="Umbraco\**" />
<Content Remove="wwwroot\Umbraco\**" />
</ItemGroup>
</Project>
+11 -7
View File
@@ -2,20 +2,24 @@
"ConnectionStrings": {
"umbracoDbDSN": ""
},
"RuntimeMinification": {
"dataFolder" : "../App_Data/Smidge",
"version" : "1"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
"Default": "Trace",
"Microsoft": "Trace",
"Microsoft.Hosting.Lifetime": "Trace"
}
},
"AllowedHosts": "*",
"Umbraco": {
"CMS": {
"Hosting": {
"Debug" : false
},
"RuntimeMinification": {
"dataFolder" : "App_Data/TEMP/Smidge",
"version" : "1"
},
"Imaging": {
"Resize": {
"MaxWidth": 5000,
@@ -8,9 +8,7 @@
var runtimeMinifier = Current.RuntimeMinifier;
runtimeMinifier.RequiresCss("assets/css/umbraco.css", "umbraco");
runtimeMinifier.RequiresCss("lib/bootstrap-social/bootstrap-social.css", "umbraco");
runtimeMinifier.RequiresCss("lib/font-awesome/css/font-awesome.min.css", "umbraco");
runtimeMinifier.RequiresCss("umbraco", "assets/css/umbraco.css", "lib/bootstrap-social/bootstrap-social.css", "lib/font-awesome/css/font-awesome.min.css");
}
<!DOCTYPE html>
@@ -18,10 +18,7 @@
}
var runtimeMinifier = Current.RuntimeMinifier;
runtimeMinifier.RequiresCss("assets/css/umbraco.css", "Umbraco");
runtimeMinifier.RequiresCss("lib/bootstrap-social/bootstrap-social.css", "Umbraco");
runtimeMinifier.RequiresCss("assets/css/umbraco.css", "Umbraco");
runtimeMinifier.RequiresCss("lib/font-awesome/css/font-awesome.min.css", "Umbraco");
runtimeMinifier.RequiresCss("Umbraco", "assets/css/umbraco.css", "lib/bootstrap-social/bootstrap-social.css", "assets/css/umbraco.css", "lib/font-awesome/css/font-awesome.min.css");
// Html
// .RequiresCss("assets/css/umbraco.css", "Umbraco")
@@ -6,7 +6,7 @@
var runtimeMinifier = Current.RuntimeMinifier;
runtimeMinifier.RequiresCss("assets/css/canvasdesigner.css", "Umbraco");
runtimeMinifier.RequiresCss("Umbraco", "assets/css/canvasdesigner.css");
}
<!DOCTYPE html>
<html lang="en">
+1 -64
View File
@@ -30,37 +30,6 @@ namespace Umbraco.Web
{
#region Collection Builders
/// <summary>
/// Gets the actions collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
internal static ActionCollectionBuilder Actions(this Composition composition)
=> composition.WithCollectionBuilder<ActionCollectionBuilder>();
/// <summary>
/// Gets the content apps collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
public static ContentAppFactoryCollectionBuilder ContentApps(this Composition composition)
=> composition.WithCollectionBuilder<ContentAppFactoryCollectionBuilder>();
/// <summary>
/// Gets the content finders collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
public static ContentFinderCollectionBuilder ContentFinders(this Composition composition)
=> composition.WithCollectionBuilder<ContentFinderCollectionBuilder>();
/// <summary>
/// Gets the editor validators collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
internal static EditorValidatorCollectionBuilder EditorValidators(this Composition composition)
=> composition.WithCollectionBuilder<EditorValidatorCollectionBuilder>();
/// <summary>
/// Gets the filtered controller factories collection builder.
@@ -70,39 +39,6 @@ namespace Umbraco.Web
public static FilteredControllerFactoryCollectionBuilder FilteredControllerFactory(this Composition composition)
=> composition.WithCollectionBuilder<FilteredControllerFactoryCollectionBuilder>();
/// <summary>
/// Gets the health checks collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static HealthCheckCollectionBuilder HealthChecks(this Composition composition)
=> composition.WithCollectionBuilder<HealthCheckCollectionBuilder>();
/// <summary>
/// Gets the TourFilters collection builder.
/// </summary>
public static TourFilterCollectionBuilder TourFilters(this Composition composition)
=> composition.WithCollectionBuilder<TourFilterCollectionBuilder>();
/// <summary>
/// Gets the url providers collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static UrlProviderCollectionBuilder UrlProviders(this Composition composition)
=> composition.WithCollectionBuilder<UrlProviderCollectionBuilder>();
/// <summary>
/// Gets the media url providers collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static MediaUrlProviderCollectionBuilder MediaUrlProviders(this Composition composition)
=> composition.WithCollectionBuilder<MediaUrlProviderCollectionBuilder>();
/// <summary>
/// Gets the backoffice sections/applications collection builder.
/// </summary>
/// <param name="composition">The composition.</param>
public static SectionCollectionBuilder Sections(this Composition composition)
=> composition.WithCollectionBuilder<SectionCollectionBuilder>();
/// <summary>
/// Gets the backoffice OEmbed Providers collection builder.
@@ -127,6 +63,7 @@ namespace Umbraco.Web
public static SearchableTreeCollectionBuilder SearchableTrees(this Composition composition)
=> composition.WithCollectionBuilder<SearchableTreeCollectionBuilder>();
#endregion
#region Uniques
@@ -242,9 +242,9 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
[MinifyJavaScriptResult(Order = 0)]
[OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)]
public JavaScriptResult Application()
public async Task<JavaScriptResult> Application()
{
var result = _runtimeMinifier.GetScriptForBackOffice();
var result = await _runtimeMinifier.GetScriptForBackOfficeAsync();
return JavaScript(result);
}
@@ -255,21 +255,22 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
[UmbracoAuthorize(Order = 0)]
[HttpGet]
public JsonNetResult GetManifestAssetList()
public async Task<JsonNetResult> GetManifestAssetList()
{
JArray GetAssetList()
async Task<JArray> GetAssetList()
{
var assets = _runtimeMinifier.GetAssetList();
var assets = new JArray(await _runtimeMinifier.GetAssetListAsync());
return new JArray(assets);
}
var assetList = await GetAssetList();
//cache the result if debugging is disabled
var result = _hostingEnvironment.IsDebugMode
? GetAssetList()
? assetList
: AppCaches.RuntimeCache.GetCacheItem<JArray>(
"Umbraco.Web.Editors.BackOfficeController.GetManifestAssetList",
GetAssetList,
() => assetList,
new TimeSpan(0, 2, 0));
return new JsonNetResult { Data = result, Formatting = Formatting.None };
+6 -3
View File
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
@@ -99,10 +100,12 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
[MinifyJavaScriptResult(Order = 0)]
[OutputCache(Order = 1, VaryByParam = "none", Location = OutputCacheLocation.Server, Duration = 5000)]
public JavaScriptResult Application()
public async Task<JavaScriptResult> Application()
{
var files = JavaScriptHelper.OptimizeScriptFiles(HttpContext, JavaScriptHelper.GetPreviewInitialization(), _runtimeMinifier);
var result = JavaScriptHelper.GetJavascriptInitialization(HttpContext, files, "umbraco.preview", _globalSettings, _ioHelper);
var files = await JavaScriptHelper.OptimizeScriptFilesAsync(HttpContext.Request.Url, JavaScriptHelper.GetPreviewInitialization(), _runtimeMinifier);
var result = JavaScriptHelper.GetJavascriptInitialization(files, "umbraco.preview", _globalSettings, _ioHelper);
return JavaScript(result);
}
@@ -130,7 +130,7 @@ namespace Umbraco.Web
public static IHtmlString AngularValueTinyMceAssets(this HtmlHelper html, IRuntimeMinifier runtimeMinifier)
{
var ctx = new HttpContextWrapper(HttpContext.Current);
var files = JavaScriptHelper.OptimizeTinyMceScriptFiles(ctx, runtimeMinifier);
var files = JavaScriptHelper.OptimizeTinyMceScriptFilesAsync(ctx.Request.Url, runtimeMinifier).GetAwaiter().GetResult();
var sb = new StringBuilder();
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Web.Mvc;
using ClientDependency.Core;
using ClientDependency.Core.CompositeFiles;
@@ -13,6 +14,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Manifest;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Runtime;
namespace Umbraco.Web.JavaScript.CDF
@@ -25,11 +27,18 @@ namespace Umbraco.Web.JavaScript.CDF
private readonly IUmbracoVersion _umbracoVersion;
private readonly IManifestParser _manifestParser;
private readonly IGlobalSettings _globalSettings;
private readonly HtmlHelper _htmlHelper;
private readonly PropertyEditorCollection _propertyEditorCollection;
public string GetHashValue => ClientDependencySettings.Instance.Version.ToString();
public ClientDependencyRuntimeMinifier(IHttpContextAccessor httpContextAccessor, IIOHelper ioHelper, ILogger logger, IUmbracoVersion umbracoVersion, IManifestParser manifestParser, IGlobalSettings globalSettings)
public ClientDependencyRuntimeMinifier(
IHttpContextAccessor httpContextAccessor,
IIOHelper ioHelper,
ILogger logger,
IUmbracoVersion umbracoVersion,
IManifestParser manifestParser,
IGlobalSettings globalSettings,
PropertyEditorCollection propertyEditorCollection)
{
_httpContextAccessor = httpContextAccessor;
_ioHelper = ioHelper;
@@ -37,7 +46,7 @@ namespace Umbraco.Web.JavaScript.CDF
_umbracoVersion = umbracoVersion;
_manifestParser = manifestParser;
_globalSettings = globalSettings;
_htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage());
_propertyEditorCollection = propertyEditorCollection;
}
private DependencyRenderer GetDependencyRenderer
@@ -55,9 +64,12 @@ namespace Umbraco.Web.JavaScript.CDF
}
public void RequiresCss(string filePath, string bundleName)
public void RequiresCss(string bundleName, params string[] filePaths)
{
GetDependencyRenderer.RegisterDependency(filePath, bundleName, ClientDependencyType.Css);
foreach (var filePath in filePaths)
{
GetDependencyRenderer.RegisterDependency(filePath, bundleName, ClientDependencyType.Css);
}
}
public string RenderCssHere(string bundleName)
@@ -79,9 +91,12 @@ namespace Umbraco.Web.JavaScript.CDF
// ClientDependencyType.Css, path));
}
public void RequiresJs(string filePath, string bundleName)
public void RequiresJs(string bundleName, params string[] filePaths)
{
GetDependencyRenderer.RegisterDependency(filePath, bundleName, ClientDependencyType.Javascript);
foreach (var filePath in filePaths)
{
GetDependencyRenderer.RegisterDependency(filePath, bundleName, ClientDependencyType.Javascript);
}
}
public string RenderJsHere(string bundleName)
@@ -101,7 +116,7 @@ namespace Umbraco.Web.JavaScript.CDF
}
public IEnumerable<string> GetAssetPaths(AssetType assetType, List<IAssetFile> attributes)
public Task<IEnumerable<string>> GetAssetPathsAsync(AssetType assetType, List<IAssetFile> attributes)
{
// get the output string for these registrations which will be processed by CDF correctly to stagger the output based
// on internal vs external resources. The output will be delimited based on our custom Umbraco.Web.JavaScript.DependencyPathRenderer
@@ -117,12 +132,12 @@ namespace Umbraco.Web.JavaScript.CDF
renderer.RegisterDependencies(dependencies, new HashSet<IClientDependencyPath>(), out var scripts, out var stylesheets, _httpContextAccessor.HttpContext);
var toParse = assetType == AssetType.Javascript ? scripts : stylesheets;
return toParse.Split(new[] { DependencyPathRenderer.Delimiter }, StringSplitOptions.RemoveEmptyEntries);
return Task.FromResult<IEnumerable<string>>(toParse.Split(new[] { DependencyPathRenderer.Delimiter }, StringSplitOptions.RemoveEmptyEntries));
}
public string Minify(string src, AssetType assetType)
public async Task<string> MinifyAsync(string fileContent, AssetType assetType)
{
TextReader reader = new StringReader(src);
TextReader reader = new StringReader(fileContent);
if (assetType == AssetType.Javascript)
{
@@ -145,27 +160,27 @@ namespace Umbraco.Web.JavaScript.CDF
var clientDependencyTempFilesDeleted = clientDependencyConfig.ClearTempFiles(_httpContextAccessor.HttpContext);
}
public string GetScriptForBackOffice()
public async Task<string> GetScriptForBackOfficeAsync()
{
var initJs = new JsInitialization(_manifestParser, this);
var initCss = new CssInitialization(_manifestParser, this);
var initJs = new JsInitialization(_manifestParser, this, _propertyEditorCollection);
var initCss = new CssInitialization(_manifestParser, this, _propertyEditorCollection);
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
var files = initJs.OptimizeBackOfficeScriptFiles(httpContext, JsInitialization.GetDefaultInitialization());
var result = JavaScriptHelper.GetJavascriptInitialization(httpContext, files, "umbraco", _globalSettings, _ioHelper);
result += initCss.GetStylesheetInitialization(httpContext);
var requestUrl = _httpContextAccessor.GetRequiredHttpContext().Request.Url;
var files = await initJs.OptimizeBackOfficeScriptFilesAsync(requestUrl, JsInitialization.GetDefaultInitialization());
var result = JavaScriptHelper.GetJavascriptInitialization(files, "umbraco", _globalSettings, _ioHelper);
result += await initCss.GetStylesheetInitializationAsync(requestUrl);
return result;
}
public IEnumerable<string> GetAssetList()
public async Task<IEnumerable<string>> GetAssetListAsync()
{
var initJs = new JsInitialization(_manifestParser, this);
var initCss = new CssInitialization(_manifestParser, this);
var initJs = new JsInitialization(_manifestParser, this, _propertyEditorCollection);
var initCss = new CssInitialization(_manifestParser, this, _propertyEditorCollection);
var assets = new List<string>();
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
assets.AddRange(initJs.OptimizeBackOfficeScriptFiles(httpContext, Enumerable.Empty<string>()));
assets.AddRange(initCss.GetStylesheetFiles(httpContext));
var requestUrl = _httpContextAccessor.GetRequiredHttpContext().Request.Url;
assets.AddRange(await initJs.OptimizeBackOfficeScriptFilesAsync(requestUrl, Enumerable.Empty<string>()));
assets.AddRange(await initCss.GetStylesheetFilesAsync(requestUrl));
return assets;
}
-136
View File
@@ -1,136 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to stop persisting the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="JsInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>jsinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="Main" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Main.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="PreviewInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>previewinitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="ServerVariables" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>servervariables.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="TinyMceInitialize" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>TinyMceInitialize.js;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>
@@ -44,7 +44,7 @@ namespace Umbraco.Web.Mvc
//minify the result
var result = jsResult.Script;
var minified = _runtimeMinifier.Minify(result, AssetType.Javascript);
var minified = _runtimeMinifier.MinifyAsync(result, AssetType.Javascript).GetAwaiter().GetResult();
jsResult.Script = minified;
}
}
@@ -209,7 +209,7 @@ namespace Umbraco.Web.Runtime
composition.MediaUrlProviders()
.Append<DefaultMediaUrlProvider>();
composition.RegisterUnique<IImageUrlGenerator, ImageProcessorImageUrlGenerator>();
composition.RegisterUnique<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
composition.RegisterUnique<IContentLastChanceFinder, ContentFinderByConfigured404>();
-31
View File
@@ -39,9 +39,6 @@
</PropertyGroup>
<PropertyGroup />
<ItemGroup>
<Reference Include="ClientDependency.Core.Mvc, Version=1.9.3.0, Culture=neutral, PublicKeyToken=null">
<HintPath>C:\Users\Berg\.nuget\packages\clientdependency-mvc5\1.9.3\lib\net45\ClientDependency.Core.Mvc.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -58,9 +55,6 @@
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>C:\Users\Bjarke\.nuget\packages\microsoft.aspnet.mvc\5.2.7\lib\net45\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web.Services" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
@@ -150,11 +144,7 @@
<Compile Include="Compose\BackOfficeUserAuditEventsComposer.cs" />
<Compile Include="Composing\CompositionExtensions\Installer.cs" />
<Compile Include="Composing\LightInject\LightInjectContainer.cs" />
<Compile Include="JavaScript\AssetInitialization.cs" />
<Compile Include="JavaScript\CDF\ClientDependencyRuntimeMinifier.cs" />
<Compile Include="JavaScript\CssInitialization.cs" />
<Compile Include="JavaScript\JavaScriptHelper.cs" />
<Compile Include="JavaScript\JsInitialization.cs" />
<Compile Include="Models\NoNodesViewModel.cs" />
<Compile Include="Mvc\RenderNoContentController.cs" />
<Compile Include="Editors\BackOfficePreviewModel.cs" />
@@ -277,7 +267,6 @@
<Compile Include="Editors\UserGroupsController.cs" />
<Compile Include="Editors\Filters\UserGroupValidateAttribute.cs" />
<Compile Include="Editors\UsersController.cs" />
<Compile Include="HybridUmbracoContextAccessor.cs" />
<Compile Include="HttpContextUmbracoContextAccessor.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Composing\CompositionExtensions\WebMappingProfiles.cs" />
@@ -388,7 +377,6 @@
<Compile Include="Editors\MemberTypeController.cs" />
<Compile Include="Editors\UpdateCheckController.cs" />
<Compile Include="Editors\StylesheetController.cs" />
<Compile Include="PropertyEditors\PropertyEditorAssetAttribute.cs" />
<Compile Include="PropertyEditors\RteEmbedController.cs" />
<Compile Include="Editors\EntityController.cs" />
<Compile Include="Editors\MemberController.cs" />
@@ -471,12 +459,6 @@
<Compile Include="Mvc\IRenderMvcController.cs" />
<Compile Include="Mvc\SurfaceRouteHandler.cs" />
<Compile Include="Security\WebSecurity.cs" />
<Compile Include="JavaScript\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="JavaScript\ServerVariablesParser.cs" />
<Compile Include="CdfLogger.cs" />
<Compile Include="Controllers\UmbLoginController.cs" />
<Compile Include="UrlHelperExtensions.cs" />
@@ -570,23 +552,10 @@
<Compile Include="Runtime\WebFinalComposer.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="JavaScript\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Mvc\Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="JavaScript\Main.js" />
<EmbeddedResource Include="JavaScript\JsInitialize.js" />
<EmbeddedResource Include="JavaScript\ServerVariables.js" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="JavaScript\PreviewInitialize.js" />
<None Include="JavaScript\TinyMceInitialize.js" />
<!--<Content Include="umbraco.presentation\umbraco\users\PermissionEditor.aspx" />-->
</ItemGroup>
<ItemGroup>
<None Include="..\Umbraco.Web.UI\Views\web.config">