Watch file changes and invalidate the bundle cache on a file change in the bundle file list.

pull/301/head
Halil ibrahim Kalkan 7 years ago
parent 0cd9d4e89d
commit c722132008

@ -7,16 +7,21 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{ {
public class BundleCache : IBundleCache, ISingletonDependency public class BundleCache : IBundleCache, ISingletonDependency
{ {
private readonly ConcurrentDictionary<string, List<string>> _cache; private readonly ConcurrentDictionary<string, BundleCacheItem> _cache;
public BundleCache() public BundleCache()
{ {
_cache = new ConcurrentDictionary<string, List<string>>(); _cache = new ConcurrentDictionary<string, BundleCacheItem>();
} }
public List<string> GetFiles(string bundleName, Func<List<string>> factory) public BundleCacheItem GetOrAdd(string bundleName, Func<BundleCacheItem> factory)
{ {
return _cache.GetOrAdd(bundleName, factory); return _cache.GetOrAdd(bundleName, factory);
} }
public bool Remove(string bundleName)
{
return _cache.TryRemove(bundleName, out _);
}
} }
} }

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{
public class BundleCacheItem
{
public List<string> Files { get; }
public List<IDisposable> WatchDisposeHandles { get; }
public BundleCacheItem(List<string> files)
{
Files = files;
WatchDisposeHandles = new List<IDisposable>();
}
}
}

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts; using Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles; using Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
@ -14,6 +15,9 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{ {
public class BundleManager : IBundleManager, ITransientDependency public class BundleManager : IBundleManager, ITransientDependency
{ {
protected IHybridWebRootFileProvider WebRootFileProvider { get; }
//TODO: Make all protected readonly to allow easily extend the bundlemanager
private readonly BundlingOptions _options; private readonly BundlingOptions _options;
private readonly IHostingEnvironment _hostingEnvironment; private readonly IHostingEnvironment _hostingEnvironment;
private readonly IScriptBundler _scriptBundler; private readonly IScriptBundler _scriptBundler;
@ -29,23 +33,25 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
IHostingEnvironment hostingEnvironment, IHostingEnvironment hostingEnvironment,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
IDynamicFileProvider dynamicFileProvider, IDynamicFileProvider dynamicFileProvider,
IBundleCache bundleCache) IBundleCache bundleCache,
IHybridWebRootFileProvider webRootFileProvider)
{ {
_hostingEnvironment = hostingEnvironment; _hostingEnvironment = hostingEnvironment;
_scriptBundler = scriptBundler; _scriptBundler = scriptBundler;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_dynamicFileProvider = dynamicFileProvider; _dynamicFileProvider = dynamicFileProvider;
_bundleCache = bundleCache; _bundleCache = bundleCache;
WebRootFileProvider = webRootFileProvider;
_styleBundler = styleBundler; _styleBundler = styleBundler;
_options = options.Value; _options = options.Value;
} }
public List<string> GetStyleBundleFiles(string bundleName) public virtual List<string> GetStyleBundleFiles(string bundleName)
{ {
return GetBundleFiles(_options.StyleBundles, bundleName, _styleBundler); return GetBundleFiles(_options.StyleBundles, bundleName, _styleBundler);
} }
public List<string> GetScriptBundleFiles(string bundleName) public virtual List<string> GetScriptBundleFiles(string bundleName)
{ {
return GetBundleFiles(_options.ScriptBundles, bundleName, _scriptBundler); return GetBundleFiles(_options.ScriptBundles, bundleName, _scriptBundler);
} }
@ -54,15 +60,24 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{ {
var bundleRelativePath = _options.BundleFolderName.EnsureEndsWith('/') + bundleName + "." + bundler.FileExtension; var bundleRelativePath = _options.BundleFolderName.EnsureEndsWith('/') + bundleName + "." + bundler.FileExtension;
return _bundleCache.GetFiles(bundleRelativePath, () => var cacheItem = _bundleCache.GetOrAdd(bundleRelativePath, () =>
{ {
var files = CreateFileList(bundles, bundleName); var files = CreateFileList(bundles, bundleName);
if (!IsBundlingEnabled()) if (!IsBundlingEnabled())
{ {
return files; return new BundleCacheItem(files);
} }
var cacheValue = new BundleCacheItem(
new List<string>
{
"/" + bundleRelativePath
}
);
WatchChanges(cacheValue, files, bundleRelativePath);
var bundleResult = bundler.Bundle( var bundleResult = bundler.Bundle(
new BundlerContext( new BundlerContext(
bundleRelativePath, bundleRelativePath,
@ -73,11 +88,33 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
SaveBundleResult(bundleRelativePath, bundleResult); SaveBundleResult(bundleRelativePath, bundleResult);
return new List<string> return cacheValue;
{
"/" + bundleRelativePath
};
}); });
return cacheItem.Files;
}
private void WatchChanges(BundleCacheItem cacheValue, List<string> files, string bundleRelativePath)
{
lock (cacheValue.WatchDisposeHandles)
{
foreach (var file in files)
{
var watchDisposeHandle = WebRootFileProvider.Watch(file).RegisterChangeCallback(_ =>
{
lock (cacheValue.WatchDisposeHandles)
{
cacheValue.WatchDisposeHandles.ForEach(h => h.Dispose());
cacheValue.WatchDisposeHandles.Clear();
}
_bundleCache.Remove(bundleRelativePath);
_dynamicFileProvider.Delete("/wwwroot/" + bundleRelativePath); //TODO: get rid of wwwroot!
}, null);
cacheValue.WatchDisposeHandles.Add(watchDisposeHandle);
}
}
} }
protected virtual void SaveBundleResult(string bundleRelativePath, BundleResult bundleResult) protected virtual void SaveBundleResult(string bundleRelativePath, BundleResult bundleResult)

@ -1,10 +1,11 @@
using System; using System;
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling
{ {
public interface IBundleCache public interface IBundleCache
{ {
List<string> GetFiles(string bundleName, Func<List<string>> factory); BundleCacheItem GetOrAdd(string bundleName, Func<BundleCacheItem> factory);
bool Remove(string bundleName);
} }
} }
Loading…
Cancel
Save