Browse Source

Refactored bundle tag helpers and bundle manager

pull/301/head
Halil ibrahim Kalkan 8 years ago
parent
commit
8c78a6ffbd
  1. 56
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpBundleTagHelperServiceBase.cs
  2. 2
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpScriptBundleTagHelper.cs
  3. 43
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpScriptBundleTagHelperService.cs
  4. 3
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpStyleBundleTagHelper.cs
  5. 44
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpStyleBundleTagHelperService.cs
  6. 7
      src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/IBundleTagHelper.cs
  7. 39
      src/Volo.Abp.AspNetCore.Mvc.UI/UI/Bundling/BundleCollection.cs
  8. 21
      src/Volo.Abp.AspNetCore.Mvc.UI/UI/Bundling/BundleManager.cs
  9. 6
      src/Volo.Abp.AspNetCore.Mvc.UI/UI/Bundling/IBundleManager.cs

56
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpBundleTagHelperServiceBase.cs

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
{
public abstract class AbpBundleTagHelperServiceBase<TTagHelper> : AbpTagHelperService<TTagHelper>
where TTagHelper : TagHelper, IBundleTagHelper
{
protected IBundleManager BundleManager { get; }
protected AbpBundleTagHelperServiceBase(IBundleManager bundleManager)
{
BundleManager = bundleManager;
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.TagName = null;
var bundleName = TagHelper.Name;
var files = await GetFileList(context, output);
if (bundleName.IsNullOrEmpty())
{
bundleName = GenerateBundleName(context, output, files);
}
CreateBundle(bundleName, files);
var bundleFiles = GetBundleFiles(bundleName);
await output.GetChildContentAsync(); //TODO: Suppress child execution!
output.Content.Clear();
AddHtmlTags(context, output, bundleFiles);
}
protected abstract void CreateBundle(string bundleName, List<string> files);
protected abstract List<string> GetBundleFiles(string bundleName);
protected abstract void AddHtmlTags(TagHelperContext context, TagHelperOutput output, List<string> files);
protected virtual string GenerateBundleName(TagHelperContext context, TagHelperOutput output, List<string> fileList)
{
return fileList.JoinAsString("|").ToMd5();
}
protected virtual async Task<List<string>> GetFileList(TagHelperContext context, TagHelperOutput output)
{
var fileList = new List<string>();
context.Items[AbpBundleFileTagHelperService.ContextFileListKey] = fileList;
await output.GetChildContentAsync();
return fileList;
}
}
}

2
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpScriptBundleTagHelper.cs

@ -3,7 +3,7 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
{ {
[HtmlTargetElement("abp-script-bundle", TagStructure = TagStructure.NormalOrSelfClosing)] [HtmlTargetElement("abp-script-bundle", TagStructure = TagStructure.NormalOrSelfClosing)]
public class AbpScriptBundleTagHelper : AbpTagHelper<AbpScriptBundleTagHelper, AbpScriptBundleTagHelperService> public class AbpScriptBundleTagHelper : AbpTagHelper<AbpScriptBundleTagHelper, AbpScriptBundleTagHelperService>, IBundleTagHelper
{ {
public string Name { get; set; } public string Name { get; set; }

43
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpScriptBundleTagHelperService.cs

@ -1,43 +1,32 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
{ {
public class AbpScriptBundleTagHelperService : AbpTagHelperService<AbpScriptBundleTagHelper> public class AbpScriptBundleTagHelperService : AbpBundleTagHelperServiceBase<AbpScriptBundleTagHelper>
{ {
private readonly IBundleManager _bundleManager;
public AbpScriptBundleTagHelperService(IBundleManager bundleManager) public AbpScriptBundleTagHelperService(IBundleManager bundleManager)
: base(bundleManager)
{ {
_bundleManager = bundleManager;
} }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) protected override void CreateBundle(string bundleName, List<string> files)
{ {
output.TagName = null; BundleManager.CreateScriptBundle(
var bundleName = TagHelper.Name;
var files = await GetFileList(context, output);
if (bundleName.IsNullOrEmpty())
{
bundleName = GenerateBundleName(context, output, files);
}
_bundleManager.CreateDynamicScriptBundle(
bundleName, bundleName,
configuration => configuration.AddFiles(files.ToArray()) configuration => configuration.AddFiles(files.ToArray())
); );
}
var bundleFiles = _bundleManager.GetScriptBundleFiles(bundleName); protected override List<string> GetBundleFiles(string bundleName)
await output.GetChildContentAsync(); //TODO: Suppress child execution! {
output.Content.Clear(); return BundleManager.GetScriptBundleFiles(bundleName);
AddLinkTags(context, output, bundleFiles);
} }
protected virtual void AddLinkTags(TagHelperContext context, TagHelperOutput output, List<string> files) protected override void AddHtmlTags(TagHelperContext context, TagHelperOutput output, List<string> files)
{ {
foreach (var file in files) foreach (var file in files)
{ {
@ -45,17 +34,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
} }
} }
protected virtual string GenerateBundleName(TagHelperContext context, TagHelperOutput output, List<string> fileList)
{
return fileList.JoinAsString("|").ToMd5();
}
protected virtual async Task<List<string>> GetFileList(TagHelperContext context, TagHelperOutput output)
{
var fileList = new List<string>();
context.Items[AbpBundleFileTagHelperService.ContextFileListKey] = fileList;
await output.GetChildContentAsync();
return fileList;
}
} }
} }

3
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpStyleBundleTagHelper.cs

@ -1,12 +1,11 @@
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.Threading;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
{ {
//TODO: Move to Volo.Abp.AspNetCore.Mvc.UI package. //TODO: Move to Volo.Abp.AspNetCore.Mvc.UI package.
[HtmlTargetElement("abp-style-bundle", TagStructure = TagStructure.NormalOrSelfClosing)] [HtmlTargetElement("abp-style-bundle", TagStructure = TagStructure.NormalOrSelfClosing)]
public class AbpStyleBundleTagHelper : AbpTagHelper<AbpStyleBundleTagHelper, AbpStyleBundleTagHelperService> public class AbpStyleBundleTagHelper : AbpTagHelper<AbpStyleBundleTagHelper, AbpStyleBundleTagHelperService>, IBundleTagHelper
{ {
public string Name { get; set; } public string Name { get; set; }

44
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/AbpStyleBundleTagHelperService.cs

@ -1,43 +1,32 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
{ {
public class AbpStyleBundleTagHelperService : AbpTagHelperService<AbpStyleBundleTagHelper> public class AbpStyleBundleTagHelperService : AbpBundleTagHelperServiceBase<AbpStyleBundleTagHelper>
{ {
private readonly IBundleManager _bundleManager;
public AbpStyleBundleTagHelperService(IBundleManager bundleManager) public AbpStyleBundleTagHelperService(IBundleManager bundleManager)
: base(bundleManager)
{ {
_bundleManager = bundleManager;
} }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) protected override void CreateBundle(string bundleName, List<string> files)
{ {
output.TagName = null; BundleManager.CreateStyleBundle(
var bundleName = TagHelper.Name;
var files = await GetFileList(context, output);
if (bundleName.IsNullOrEmpty())
{
bundleName = GenerateBundleName(context, output, files);
}
_bundleManager.CreateDynamicStyleBundle(
bundleName, bundleName,
configuration => configuration.AddFiles(files.ToArray()) configuration => configuration.AddFiles(files.ToArray())
); );
}
var bundleFiles = _bundleManager.GetStyleBundleFiles(bundleName); protected override List<string> GetBundleFiles(string bundleName)
await output.GetChildContentAsync(); //TODO: Suppress child execution! {
output.Content.Clear(); return BundleManager.GetStyleBundleFiles(bundleName);
AddLinkTags(context, output, bundleFiles);
} }
protected virtual void AddLinkTags(TagHelperContext context, TagHelperOutput output, List<string> files) protected override void AddHtmlTags(TagHelperContext context, TagHelperOutput output, List<string> files)
{ {
foreach (var file in files) foreach (var file in files)
{ {
@ -45,18 +34,5 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
$"<link rel=\"stylesheet\" type=\"text/css\" href=\"{file}\" />{Environment.NewLine}"); $"<link rel=\"stylesheet\" type=\"text/css\" href=\"{file}\" />{Environment.NewLine}");
} }
} }
protected virtual string GenerateBundleName(TagHelperContext context, TagHelperOutput output, List<string> fileList)
{
return fileList.JoinAsString("|").ToMd5();
}
protected virtual async Task<List<string>> GetFileList(TagHelperContext context, TagHelperOutput output)
{
var fileList = new List<string>();
context.Items[AbpBundleFileTagHelperService.ContextFileListKey] = fileList;
await output.GetChildContentAsync();
return fileList;
}
} }
} }

7
src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Bundling/IBundleTagHelper.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Bundling
{
public interface IBundleTagHelper
{
string Name { get; }
}
}

39
src/Volo.Abp.AspNetCore.Mvc.UI/UI/Bundling/BundleCollection.cs

@ -1,18 +1,18 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{ {
public class BundleCollection public class BundleCollection
{ {
private readonly Dictionary<string, BundleConfiguration> _bundleContributors; private readonly ConcurrentDictionary<string, BundleConfiguration> _bundleContributors;
public BundleCollection() public BundleCollection()
{ {
_bundleContributors = new Dictionary<string, BundleConfiguration>(); _bundleContributors = new ConcurrentDictionary<string, BundleConfiguration>();
} }
//TODO: Seperate to Add and WithFiles/WithContributors methods instead of coupling
public BundleConfiguration Add(string bundleName) public BundleConfiguration Add(string bundleName)
{ {
if (_bundleContributors.ContainsKey(bundleName)) if (_bundleContributors.ContainsKey(bundleName))
@ -20,43 +20,40 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
throw new AbpException($"There is already a bundle added with given {nameof(bundleName)}: {bundleName}"); throw new AbpException($"There is already a bundle added with given {nameof(bundleName)}: {bundleName}");
} }
var bundleConfiguration = new BundleConfiguration(bundleName); return _bundleContributors.AddOrUpdate(bundleName, new BundleConfiguration(bundleName), (n, c) => c);
_bundleContributors.Add(bundleName, bundleConfiguration);
return bundleConfiguration;
} }
public BundleConfiguration Get(string bundleName) public BundleConfiguration Get(string bundleName)
{ {
if (!_bundleContributors.ContainsKey(bundleName)) CheckBundle(bundleName);
{
throw new AbpException($"There is no bundle added with given {nameof(bundleName)}: {bundleName}");
}
return _bundleContributors[bundleName]; return _bundleContributors[bundleName];
} }
public BundleConfiguration GetOrAdd(string bundleName, Action<BundleConfiguration> configureAction = null) public BundleConfiguration GetOrAdd(string bundleName)
{
return GetOrAdd(bundleName, c => { });
}
internal BundleConfiguration GetOrAdd(string bundleName, Action<BundleConfiguration> configureAction)
{ {
return _bundleContributors.GetOrAdd( return _bundleContributors.GetOrAdd(
bundleName, bundleName,
() => () =>
{ {
var configuration = new BundleConfiguration(bundleName); var configuration = new BundleConfiguration(bundleName);
configureAction?.Invoke(configuration); configureAction.Invoke(configuration);
return configuration; return configuration;
}); });
} }
public List<string> GetFiles(string bundleName) public List<string> GetFiles(string bundleName)
{ {
var bundleConfiguration = _bundleContributors.GetOrDefault(bundleName); CheckBundle(bundleName);
if (bundleConfiguration == null)
{
throw new AbpException("Undefined bundle: " + bundleName);
}
var files = new List<string>(); var files = new List<string>();
var bundleConfiguration = _bundleContributors[bundleName];
foreach (var contributor in bundleConfiguration.Contributors) foreach (var contributor in bundleConfiguration.Contributors)
{ {
contributor.Contribute(files); contributor.Contribute(files);
@ -64,5 +61,13 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
return files; return files;
} }
private void CheckBundle(string bundleName)
{
if (!_bundleContributors.ContainsKey(bundleName))
{
throw new AbpException($"There is no bundle with given {nameof(bundleName)}: {bundleName}");
}
}
} }
} }

21
src/Volo.Abp.AspNetCore.Mvc.UI/UI/Bundling/BundleManager.cs

@ -34,31 +34,16 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
public List<string> GetScriptBundleFiles(string bundleName) public List<string> GetScriptBundleFiles(string bundleName)
{ {
//if (_hostingEnvironment.IsDevelopment()) return _options.ScriptBundles.GetFiles(bundleName);
{
return _options.ScriptBundles.GetFiles(bundleName);
}
return new List<string>
{
_cache.GetOrAdd(
"SCRIPT:" + bundleName,
() => _bundler.CreateBundle(
_options.ScriptBundles.GetFiles(bundleName)
)
)
};
} }
public void CreateDynamicStyleBundle(string bundleName, Action<BundleConfiguration> configureAction) public void CreateStyleBundle(string bundleName, Action<BundleConfiguration> configureAction)
{ {
//TODO: How to handle concurrency!
_options.StyleBundles.GetOrAdd(bundleName, configureAction); _options.StyleBundles.GetOrAdd(bundleName, configureAction);
} }
public void CreateDynamicScriptBundle(string bundleName, Action<BundleConfiguration> configureAction) public void CreateScriptBundle(string bundleName, Action<BundleConfiguration> configureAction)
{ {
//TODO: How to handle concurrency!
_options.ScriptBundles.GetOrAdd(bundleName, configureAction); _options.ScriptBundles.GetOrAdd(bundleName, configureAction);
} }
} }

6
src/Volo.Abp.AspNetCore.Mvc.UI/UI/Bundling/IBundleManager.cs

@ -3,14 +3,16 @@ using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{ {
//TODO: Bundle system needs refactoring/redesign
public interface IBundleManager public interface IBundleManager
{ {
List<string> GetStyleBundleFiles(string bundleName); List<string> GetStyleBundleFiles(string bundleName);
List<string> GetScriptBundleFiles(string bundleName); List<string> GetScriptBundleFiles(string bundleName);
void CreateDynamicStyleBundle(string bundleName, Action<BundleConfiguration> configureAction); void CreateStyleBundle(string bundleName, Action<BundleConfiguration> configureAction);
void CreateDynamicScriptBundle(string bundleName, Action<BundleConfiguration> configureAction); void CreateScriptBundle(string bundleName, Action<BundleConfiguration> configureAction);
} }
} }
Loading…
Cancel
Save