Browse Source

Merge pull request #22333 from abpframework/maui-global-bundle

Make Bundling system support MAUI Blazor
pull/22415/head
maliming 11 months ago
committed by GitHub
parent
commit
940ddfb712
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      Directory.Packages.props
  2. 5
      build/common.ps1
  3. 15
      framework/Volo.Abp.sln
  4. 19
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo.Abp.AspNetCore.Bundling.csproj
  5. 15
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/AbpAspNetCoreBundlingModule.cs
  6. 3
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleCache.cs
  7. 3
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleCacheItem.cs
  8. 248
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleManagerBase.cs
  9. 2
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleResult.cs
  10. 14
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundlerBase.cs
  11. 2
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundlerContext.cs
  12. 2
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundleCache.cs
  13. 3
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundleManager.cs
  14. 4
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundler.cs
  15. 2
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundlerContext.cs
  16. 6
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/Scripts/IScriptBundler.cs
  17. 6
      framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/Styles/IStyleBundler.cs
  18. 106
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/AbpAspNetCoreComponentsMauiBlazorBundlingModule.cs
  19. 13
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/AbpBlazorWebView.cs
  20. 125
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/BundleManager.cs
  21. 8
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/IMauiBlazorContentFileProvide.cs
  22. 26
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/MauiBlazorBundlerBase.cs
  23. 65
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/MauiBlazorContentFileProvider.cs
  24. 28
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Scripts/ScriptBundler.cs
  25. 40
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Styles/StyleBundler.cs
  26. 41
      framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling.csproj
  27. 2
      framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorServerComponentBundleManager.cs
  28. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpBundleContributorOptions.cs
  29. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj
  30. 4
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpAspNetCoreMvcUiBundlingModule.cs
  31. 233
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs
  32. 25
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/MvcUiBundlerBase.cs
  33. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Scripts/IScriptBundler.cs
  34. 8
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Scripts/ScriptBundler.cs
  35. 6
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/IStyleBundler.cs
  36. 11
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/StyleBundler.cs
  37. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs
  38. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs
  39. 1
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs
  40. 2
      nupkg/common.ps1

2
Directory.Packages.props

@ -61,6 +61,8 @@
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Components.WebView.Maui" Version="9.0.30" />
<PackageVersion Include="Microsoft.Maui.Controls" Version="9.0.30" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="9.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.0" />

5
build/common.ps1

@ -23,6 +23,11 @@ $solutionPaths = @(
"../modules/blob-storing-database"
)
# Remove MAUI related projects if not on Windows
if ($env:OS -ne "Windows_NT") {
dotnet sln ../framework/Volo.Abp.sln remove ../framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling.csproj
}
if ($full -eq "-f")
{
# List of additional solutions required for full build

15
framework/Volo.Abp.sln

@ -470,6 +470,7 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Bundling", "src\Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Bundling\Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Bundling.csproj", "{2F9BA650-395C-4BE0-8CCB-9978E753562A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.Bundling", "src\Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.Bundling\Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.Bundling.csproj", "{7ADB6D92-82CC-4A2A-8BCF-FC6C6308796D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Google", "src\Volo.Abp.BlobStoring.Google\Volo.Abp.BlobStoring.Google.csproj", "{DEEB5200-BBF9-464D-9B7E-8FC035A27E94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Google.Tests", "test\Volo.Abp.BlobStoring.Google.Tests\Volo.Abp.BlobStoring.Google.Tests.csproj", "{40FB8907-9CF7-44D0-8B5F-538AC6DAF8B9}"
@ -480,6 +481,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Sms.TencentCloud",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Sms.TencentCloud.Tests", "test\Volo.Abp.Sms.TencenCloud.Tests\Volo.Abp.Sms.TencentCloud.Tests.csproj", "{C753DDD6-5699-45F8-8669-08CE0BB816DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Bundling", "src\Volo.Abp.AspNetCore.Bundling\Volo.Abp.AspNetCore.Bundling.csproj", "{75AA8A90-B3F6-43DF-ADA7-0990DEF44E2C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling", "src\Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling\Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling.csproj", "{70720321-DED4-464F-B913-BDA5BBDD7982}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1434,6 +1439,14 @@ Global
{C753DDD6-5699-45F8-8669-08CE0BB816DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C753DDD6-5699-45F8-8669-08CE0BB816DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C753DDD6-5699-45F8-8669-08CE0BB816DE}.Release|Any CPU.Build.0 = Release|Any CPU
{75AA8A90-B3F6-43DF-ADA7-0990DEF44E2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75AA8A90-B3F6-43DF-ADA7-0990DEF44E2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75AA8A90-B3F6-43DF-ADA7-0990DEF44E2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75AA8A90-B3F6-43DF-ADA7-0990DEF44E2C}.Release|Any CPU.Build.0 = Release|Any CPU
{70720321-DED4-464F-B913-BDA5BBDD7982}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70720321-DED4-464F-B913-BDA5BBDD7982}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70720321-DED4-464F-B913-BDA5BBDD7982}.Release|Any CPU.ActiveCfg = Release|Any CPU
{70720321-DED4-464F-B913-BDA5BBDD7982}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1676,6 +1689,8 @@ Global
{E50739A7-5E2F-4EB5-AEA9-554115CB9613} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{BE7109C5-7368-4688-8557-4A15D3F4776A} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{C753DDD6-5699-45F8-8669-08CE0BB816DE} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{75AA8A90-B3F6-43DF-ADA7-0990DEF44E2C} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{70720321-DED4-464F-B913-BDA5BBDD7982} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

19
framework/src/Volo.Abp.AspNetCore.Bundling/Volo.Abp.AspNetCore.Bundling.csproj

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Minify\Volo.Abp.Minify.csproj" />
<ProjectReference Include="..\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions\Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj" />
</ItemGroup>
</Project>

15
framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/AbpAspNetCoreBundlingModule.cs

@ -0,0 +1,15 @@
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Minify;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Bundling;
[DependsOn(
typeof(AbpAspNetCoreMvcUiBundlingAbstractionsModule),
typeof(AbpMinifyModule),
typeof(AbpVirtualFileSystemModule)
)]
public class AbpAspNetCoreBundlingModule : AbpModule
{
}

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleCache.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleCache.cs

@ -1,9 +1,10 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public class BundleCache : IBundleCache, ISingletonDependency
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleCacheItem.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleCacheItem.cs

@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public class BundleCacheItem
{

248
framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleManagerBase.cs

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling.Scripts;
using Volo.Abp.AspNetCore.Bundling.Styles;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Bundling;
public abstract class BundleManagerBase : IBundleManager
{
public ILogger<BundleManagerBase> Logger { get; set; }
protected readonly AbpBundlingOptions Options;
protected readonly AbpBundleContributorOptions ContributorOptions;
protected readonly IScriptBundler ScriptBundler;
protected readonly IStyleBundler StyleBundler;
protected readonly IServiceProvider ServiceProvider;
protected readonly IDynamicFileProvider DynamicFileProvider;
protected readonly IBundleCache BundleCache;
public BundleManagerBase(
IOptions<AbpBundlingOptions> options,
IOptions<AbpBundleContributorOptions> contributorOptions,
IScriptBundler scriptBundler,
IStyleBundler styleBundler,
IServiceProvider serviceProvider,
IDynamicFileProvider dynamicFileProvider,
IBundleCache bundleCache)
{
Options = options.Value;
ContributorOptions = contributorOptions.Value;
ScriptBundler = scriptBundler;
ServiceProvider = serviceProvider;
DynamicFileProvider = dynamicFileProvider;
BundleCache = bundleCache;
StyleBundler = styleBundler;
Logger = NullLogger<BundleManagerBase>.Instance;
}
public virtual async Task<IReadOnlyList<BundleFile>> GetStyleBundleFilesAsync(string bundleName)
{
return await GetBundleFilesAsync(Options.StyleBundles, bundleName, StyleBundler);
}
public virtual async Task<IReadOnlyList<BundleFile>> GetScriptBundleFilesAsync(string bundleName)
{
return await GetBundleFilesAsync(Options.ScriptBundles, bundleName, ScriptBundler);
}
protected virtual async Task<IReadOnlyList<BundleFile>> GetBundleFilesAsync(BundleConfigurationCollection bundles,
string bundleName, IBundler bundler)
{
var files = new List<BundleFile>();
var contributors = GetContributors(bundles, bundleName);
var bundleFiles = await GetBundleFilesAsync(contributors);
var dynamicResources = await GetDynamicResourcesAsync(contributors);
if (!IsBundlingEnabled())
{
return bundleFiles.Union(dynamicResources).ToImmutableList();
}
var localBundleFiles = new List<string>();
foreach (var bundleFile in bundleFiles)
{
if (!bundleFile.IsExternalFile)
{
localBundleFiles.Add(bundleFile.FileName);
}
else
{
if (localBundleFiles.Count != 0)
{
files.AddRange(AddToBundleCache(bundleName, bundler, localBundleFiles).Files);
localBundleFiles.Clear();
}
files.Add(bundleFile);
}
}
if (localBundleFiles.Count != 0)
{
files.AddRange(AddToBundleCache(bundleName, bundler, localBundleFiles).Files);
}
return files.Union(dynamicResources).ToImmutableList();
}
private BundleCacheItem AddToBundleCache(string bundleName, IBundler bundler, List<string> bundleFiles)
{
var bundleRelativePath =
Options.BundleFolderName.EnsureEndsWith('/') +
bundleName + "." + bundleFiles.JoinAsString("|").ToMd5() + "." + bundler.FileExtension;
return BundleCache.GetOrAdd(bundleRelativePath, () =>
{
var cacheValue = new BundleCacheItem(
new List<BundleFile> { new BundleFile("/" + bundleRelativePath) }
);
WatchChanges(cacheValue, bundleFiles, bundleRelativePath);
var bundleResult = bundler.Bundle(
new BundlerContext(
bundleRelativePath,
bundleFiles,
IsMinficationEnabled()
)
);
SaveBundleResult(bundleRelativePath, bundleResult);
return cacheValue;
});
}
private void WatchChanges(BundleCacheItem cacheValue, List<string> files, string bundleRelativePath)
{
lock (cacheValue.WatchDisposeHandles)
{
foreach (var file in files)
{
var watchDisposeHandle = GetFileProvider().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)
{
var fileName = bundleRelativePath.Substring(bundleRelativePath.IndexOf('/') + 1);
DynamicFileProvider.AddOrUpdate(
new InMemoryFileInfo(
"/wwwroot/" + bundleRelativePath, //TODO: get rid of wwwroot!
Encoding.UTF8.GetBytes(bundleResult.Content),
fileName
)
);
}
public abstract bool IsBundlingEnabled();
protected abstract bool IsMinficationEnabled();
protected virtual async Task<List<BundleFile>> GetBundleFilesAsync(List<IBundleContributor> contributors)
{
var context = CreateBundleConfigurationContext();
foreach (var contributor in contributors)
{
await contributor.PreConfigureBundleAsync(context);
}
foreach (var contributor in contributors)
{
await contributor.ConfigureBundleAsync(context);
}
foreach (var contributor in contributors)
{
await contributor.PostConfigureBundleAsync(context);
}
return context.Files;
}
protected virtual async Task<List<BundleFile>> GetDynamicResourcesAsync(List<IBundleContributor> contributors)
{
var context = CreateBundleConfigurationContext();
foreach (var contributor in contributors)
{
await contributor.ConfigureDynamicResourcesAsync(context);
}
return context.Files;
}
protected virtual BundleConfigurationContext CreateBundleConfigurationContext()
{
return new BundleConfigurationContext(ServiceProvider, GetFileProvider(),
Options.Parameters);
}
protected abstract IFileProvider GetFileProvider();
protected virtual List<IBundleContributor> GetContributors(BundleConfigurationCollection bundles, string bundleName)
{
var contributors = new List<IBundleContributor>();
AddContributorsWithBaseBundles(contributors, bundles, bundleName);
for (var i = 0; i < contributors.Count; ++i)
{
var extensions = ContributorOptions.Extensions(contributors[i].GetType()).GetAll();
if (extensions.Count > 0)
{
contributors.InsertRange(i + 1, extensions);
i += extensions.Count;
}
}
return contributors;
}
protected virtual void AddContributorsWithBaseBundles(List<IBundleContributor> contributors,
BundleConfigurationCollection bundles, string bundleName)
{
var bundleConfiguration = bundles.Get(bundleName);
foreach (var baseBundleName in bundleConfiguration.BaseBundles)
{
AddContributorsWithBaseBundles(contributors, bundles, baseBundleName); //Recursive call
}
var selfContributors = bundleConfiguration.Contributors.GetAll();
if (selfContributors.Any())
{
contributors.AddRange(selfContributors);
}
}
}

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleResult.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundleResult.cs

@ -1,4 +1,4 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public class BundleResult
{

14
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundlerBase.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundlerBase.cs

@ -1,31 +1,27 @@
using System;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Minify;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public abstract class BundlerBase : IBundler, ITransientDependency
{
private static string[] _minFileSuffixes = { "min", "prod" };
public ILogger<BundlerBase> Logger { get; set; }
protected IWebHostEnvironment HostEnvironment { get; }
protected IMinifier Minifier { get; }
protected AbpBundlingOptions BundlingOptions { get; }
protected BundlerBase(
IWebHostEnvironment hostEnvironment,
IMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions)
{
HostEnvironment = hostEnvironment;
Minifier = minifier;
BundlingOptions = bundlingOptions.Value;
@ -123,7 +119,7 @@ public abstract class BundlerBase : IBundler, ITransientDependency
protected virtual IFileInfo GetFileInfo(IBundlerContext context, string file)
{
var fileInfo = HostEnvironment.WebRootFileProvider.GetFileInfo(file);
var fileInfo = FindFileInfo(file);
if (!fileInfo.Exists)
{
@ -150,7 +146,7 @@ public abstract class BundlerBase : IBundler, ITransientDependency
{
foreach (var suffix in _minFileSuffixes)
{
var fileInfo = HostEnvironment.WebRootFileProvider.GetFileInfo(
var fileInfo = FindFileInfo(
$"{file.RemovePostFix($".{FileExtension}")}.{suffix}.{FileExtension}"
);
@ -163,6 +159,8 @@ public abstract class BundlerBase : IBundler, ITransientDependency
return null;
}
protected abstract IFileInfo FindFileInfo(string file);
protected virtual string ProcessBeforeAddingToTheBundle(IBundlerContext context, string filePath, string fileContent)
{
return fileContent;

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundlerContext.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/BundlerContext.cs

@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public class BundlerContext : IBundlerContext
{

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/IBundleCache.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundleCache.cs

@ -1,6 +1,6 @@
using System;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public interface IBundleCache
{

3
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/IBundleManager.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundleManager.cs

@ -1,7 +1,8 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public interface IBundleManager
{

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/IBundler.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundler.cs

@ -1,4 +1,6 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public interface IBundler
{

2
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/IBundlerContext.cs → framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/IBundlerContext.cs

@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
namespace Volo.Abp.AspNetCore.Bundling;
public interface IBundlerContext
{

6
framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/Scripts/IScriptBundler.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AspNetCore.Bundling.Scripts;
public interface IScriptBundler : IBundler
{
}

6
framework/src/Volo.Abp.AspNetCore.Bundling/Volo/Abp/AspNetCore/Bundling/Styles/IStyleBundler.cs

@ -0,0 +1,6 @@
namespace Volo.Abp.AspNetCore.Bundling.Styles;
public interface IStyleBundler : IBundler
{
}

106
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/AbpAspNetCoreComponentsMauiBlazorBundlingModule.cs

@ -0,0 +1,106 @@
using System.Text;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Bundling.Styles;
using Volo.Abp.Modularity;
using Volo.Abp.Threading;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling;
[DependsOn(
typeof(AbpAspNetCoreComponentsMauiBlazorModule),
typeof(AbpAspNetCoreBundlingModule)
)]
public class AbpAspNetCoreComponentsMauiBlazorBundlingModule : AbpModule
{
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context));
}
public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
{
await InitialGlobalAssetsAsync(context);
}
protected virtual async Task InitialGlobalAssetsAsync(ApplicationInitializationContext context)
{
var bundlingOptions = context.ServiceProvider.GetRequiredService<IOptions<AbpBundlingOptions>>().Value;
var logger = context.ServiceProvider.GetRequiredService<ILogger<AbpAspNetCoreComponentsMauiBlazorBundlingModule>>();
if (!bundlingOptions.GlobalAssets.Enabled)
{
return;
}
var bundleManager = context.ServiceProvider.GetRequiredService<BundleManager>();
var mauiBlazorContentFileProvider = context.ServiceProvider.GetRequiredService<IMauiBlazorContentFileProvider>();
var dynamicFileProvider = context.ServiceProvider.GetRequiredService<IDynamicFileProvider>();
if (!bundlingOptions.GlobalAssets.GlobalStyleBundleName.IsNullOrWhiteSpace())
{
var styleFiles = await bundleManager.GetStyleBundleFilesAsync(bundlingOptions.GlobalAssets.GlobalStyleBundleName);
var styles = string.Empty;
foreach (var file in styleFiles)
{
var fileInfo = mauiBlazorContentFileProvider.GetFileInfo(file.FileName);
if (!fileInfo.Exists)
{
logger.LogError($"Could not find the file: {file.FileName}");
continue;
}
var fileContent = await fileInfo.ReadAsStringAsync();
if (!bundleManager.IsBundlingEnabled())
{
fileContent = CssRelativePath.Adjust(fileContent,
file.FileName,
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"));
styles += $"/*{file.FileName}*/{Environment.NewLine}{fileContent}{Environment.NewLine}{Environment.NewLine}";
}
else
{
styles += $"{fileContent}{Environment.NewLine}{Environment.NewLine}";
}
}
dynamicFileProvider.AddOrUpdate(
new InMemoryFileInfo("/wwwroot/" + bundlingOptions.GlobalAssets.CssFileName,
Encoding.UTF8.GetBytes(styles),
bundlingOptions.GlobalAssets.CssFileName));
}
if (!bundlingOptions.GlobalAssets.GlobalScriptBundleName.IsNullOrWhiteSpace())
{
var scriptFiles = await bundleManager.GetScriptBundleFilesAsync(bundlingOptions.GlobalAssets.GlobalScriptBundleName);
var scripts = string.Empty;
foreach (var file in scriptFiles)
{
var fileInfo = mauiBlazorContentFileProvider.GetFileInfo(file.FileName);
if (!fileInfo.Exists)
{
logger.LogError($"Could not find the file: {file.FileName}");
continue;
}
var fileContent = await fileInfo.ReadAsStringAsync();
if (!bundleManager.IsBundlingEnabled())
{
scripts += $"{fileContent.EnsureEndsWith(';')}{Environment.NewLine}{Environment.NewLine}";
}
else
{
scripts += $"//{file.FileName}{Environment.NewLine}{fileContent.EnsureEndsWith(';')}{Environment.NewLine}{Environment.NewLine}";
}
}
dynamicFileProvider.AddOrUpdate(
new InMemoryFileInfo("/wwwroot/" + bundlingOptions.GlobalAssets.JavaScriptFileName,
Encoding.UTF8.GetBytes(scripts),
bundlingOptions.GlobalAssets.JavaScriptFileName));
}
}
}

13
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/AbpBlazorWebView.cs

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Components.WebView.Maui;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling;
public class AbpBlazorWebView : BlazorWebView
{
public override IFileProvider CreateFileProvider(string contentRootDir)
{
return new CompositeFileProvider(Handler!.GetRequiredService<IMauiBlazorContentFileProvider>(), base.CreateFileProvider(contentRootDir));
}
}

125
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/BundleManager.cs

@ -0,0 +1,125 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Bundling.Scripts;
using Volo.Abp.AspNetCore.Bundling.Styles;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling;
public class BundleManager : BundleManagerBase, ITransientDependency
{
protected IMauiBlazorContentFileProvider MauiBlazorContentFileProvider { get; }
public BundleManager(
IOptions<AbpBundlingOptions> options,
IOptions<AbpBundleContributorOptions> contributorOptions,
IScriptBundler scriptBundler,
IStyleBundler styleBundler,
IServiceProvider serviceProvider,
IDynamicFileProvider dynamicFileProvider,
IBundleCache bundleCache,
IMauiBlazorContentFileProvider mauiBlazorContentFileProvider) : base(
options,
contributorOptions,
scriptBundler,
styleBundler,
serviceProvider,
dynamicFileProvider,
bundleCache)
{
MauiBlazorContentFileProvider = mauiBlazorContentFileProvider;
}
public override bool IsBundlingEnabled()
{
switch (Options.Mode)
{
case BundlingMode.None:
return false;
case BundlingMode.Bundle:
case BundlingMode.BundleAndMinify:
return true;
case BundlingMode.Auto:
return !IsDebug();
default:
throw new AbpException($"Unhandled {nameof(BundlingMode)}: {Options.Mode}");
}
}
protected async override Task<List<BundleFile>> GetBundleFilesAsync(List<IBundleContributor> contributors)
{
var files = await base.GetBundleFilesAsync(contributors);
foreach (var file in files)
{
await CopyFileToAppDataDirectoryAsync(file);
}
return files;
}
protected virtual async Task CopyFileToAppDataDirectoryAsync(BundleFile file)
{
if (file.IsExternalFile)
{
return;
}
var fileName = Path.Combine("wwwroot", file.FileName);
if(MauiBlazorContentFileProvider.GetFileInfo(fileName).Exists)
{
return;
}
try
{
await using var inputStream = await FileSystem.Current.OpenAppPackageFileAsync(fileName);
var targetFile = Path.Combine(FileSystem.Current.AppDataDirectory, fileName);
var fileDirectory = Path.GetDirectoryName(targetFile)!;
if (!Path.Exists(fileDirectory))
{
Directory.CreateDirectory(fileDirectory);
}
await using var outputStream = File.Create(targetFile);
await inputStream.CopyToAsync(outputStream);
}
catch (Exception e)
{
Logger.LogError($"Could not copy the file to the app data directory: {fileName}", e);
}
}
protected override bool IsMinficationEnabled()
{
switch (Options.Mode)
{
case BundlingMode.None:
case BundlingMode.Bundle:
return false;
case BundlingMode.BundleAndMinify:
return true;
case BundlingMode.Auto:
return !IsDebug();
default:
throw new AbpException($"Unhandled {nameof(BundlingMode)}: {Options.Mode}");
}
}
protected virtual bool IsDebug()
{
#if DEBUG
return true;
#else
retur false;
#endif
}
protected override IFileProvider GetFileProvider()
{
return MauiBlazorContentFileProvider;
}
}

8
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/IMauiBlazorContentFileProvide.cs

@ -0,0 +1,8 @@
using Microsoft.Extensions.FileProviders;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling;
public interface IMauiBlazorContentFileProvider : IFileProvider
{
string ContentRootPath { get; }
}

26
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/MauiBlazorBundlerBase.cs

@ -0,0 +1,26 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Minify;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling;
public abstract class MauiBlazorBundlerBase : BundlerBase
{
protected IMauiBlazorContentFileProvider MauiBlazorContentFileProvider { get; }
public MauiBlazorBundlerBase(
IMauiBlazorContentFileProvider mauiBlazorContentFileProvider,
IMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions) : base(minifier,
bundlingOptions)
{
MauiBlazorContentFileProvider = mauiBlazorContentFileProvider;
}
protected override IFileInfo FindFileInfo(string file)
{
return MauiBlazorContentFileProvider.GetFileInfo(file);
}
}

65
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/MauiBlazorContentFileProvider.cs

@ -0,0 +1,65 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using Microsoft.Maui.Controls.PlatformConfiguration;
using Volo.Abp.DependencyInjection;
using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling;
public class MauiBlazorContentFileProvider : IMauiBlazorContentFileProvider, ISingletonDependency
{
private readonly IVirtualFileProvider _virtualFileProvider;
private readonly IFileProvider _fileProvider;
private string _rootPath = "/wwwroot";
public MauiBlazorContentFileProvider(IVirtualFileProvider virtualFileProvider)
{
_virtualFileProvider = virtualFileProvider;
_fileProvider = CreateFileProvider();
}
public string ContentRootPath => FileSystem.Current.AppDataDirectory;
public IFileInfo GetFileInfo(string subpath)
{
if (string.IsNullOrEmpty(subpath))
{
return new NotFoundFileInfo(subpath);
}
var fileInfo = _fileProvider.GetFileInfo(subpath);
return fileInfo.Exists ? fileInfo : _fileProvider.GetFileInfo( _rootPath + subpath.EnsureStartsWith('/'));
}
public IDirectoryContents GetDirectoryContents(string subpath)
{
if (string.IsNullOrEmpty(subpath))
{
return NotFoundDirectoryContents.Singleton;
}
var directory = _fileProvider.GetDirectoryContents(subpath);
return directory.Exists ? directory : _fileProvider.GetDirectoryContents( _rootPath + subpath.EnsureStartsWith('/'));
}
public IChangeToken Watch(string filter)
{
return new CompositeChangeToken(
[
_fileProvider.Watch(_rootPath + filter),
_fileProvider.Watch(filter)
]
);
}
protected virtual IFileProvider CreateFileProvider()
{
var assetsDirectory = Path.Combine(ContentRootPath, _rootPath.TrimStart('/'));
if (!Path.Exists(assetsDirectory))
{
Directory.CreateDirectory(assetsDirectory);
}
return new CompositeFileProvider(new PhysicalFileProvider(assetsDirectory), _virtualFileProvider);
}
}

28
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Scripts/ScriptBundler.cs

@ -0,0 +1,28 @@
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Bundling.Scripts;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Minify.Scripts;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling.Scripts;
public class ScriptBundler : MauiBlazorBundlerBase, IScriptBundler
{
public override string FileExtension => "js";
public ScriptBundler(
IMauiBlazorContentFileProvider mauiBlazorContentFileProvider,
IJavascriptMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions)
: base(
mauiBlazorContentFileProvider,
minifier,
bundlingOptions)
{
}
protected override string ProcessBeforeAddingToTheBundle(IBundlerContext context, string filePath, string fileContent)
{
return fileContent.EnsureEndsWith(';') + Environment.NewLine;
}
}

40
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Styles/StyleBundler.cs

@ -0,0 +1,40 @@
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Bundling.Styles;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.Bundling.Styles;
using Volo.Abp.Minify.Styles;
namespace Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling.Styles;
public class StyleBundler : MauiBlazorBundlerBase, IStyleBundler
{
private readonly IMauiBlazorContentFileProvider _mauiBlazorContentFileProvider;
public override string FileExtension => "css";
public StyleBundler(
IMauiBlazorContentFileProvider mauiBlazorContentFileProvider,
ICssMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions)
: base(
mauiBlazorContentFileProvider,
minifier,
bundlingOptions)
{
_mauiBlazorContentFileProvider = mauiBlazorContentFileProvider;
}
public string GetAbsolutePath(string relativePath)
{
return Path.Combine(_mauiBlazorContentFileProvider.ContentRootPath, "wwwroot", relativePath.RemovePreFix("/")).Replace("file://", "");
}
protected override string ProcessBeforeAddingToTheBundle(IBundlerContext context, string filePath, string fileContent)
{
return CssRelativePath.Adjust(
fileContent,
GetAbsolutePath(filePath),
GetAbsolutePath(context.BundleRelativePath)
);
}
}

41
framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling.csproj

@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Maui" />
<PackageReference Include="Microsoft.Maui.Controls"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.AspNetCore.Bundling\Volo.Abp.AspNetCore.Bundling.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Components.MauiBlazor\Volo.Abp.AspNetCore.Components.MauiBlazor.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Platforms\Android\" />
<Folder Include="Platforms\iOS\" />
<Folder Include="Platforms\MacCatalyst\" />
<Folder Include="Platforms\Windows\" />
</ItemGroup>
</Project>

2
framework/src/Volo.Abp.AspNetCore.Components.Server.Theming/Bundling/BlazorServerComponentBundleManager.cs

@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Components.Web.Theming.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Components.Server.Theming.Bundling;

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpBundleContributorOptions.cs → framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpBundleContributorOptions.cs

@ -1,6 +1,6 @@
using System;
using System;
using System.Collections.Concurrent;
using JetBrains.Annotations;
using System.Diagnostics.CodeAnalysis;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
@ -27,4 +27,4 @@ public class AbpBundleContributorOptions
_ => new BundleContributorCollection()
);
}
}
}

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo.Abp.AspNetCore.Mvc.UI.Bundling.csproj

@ -19,6 +19,7 @@
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap\Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions\Volo.Abp.AspNetCore.Mvc.UI.Bundling.Abstractions.csproj" />
<ProjectReference Include="..\Volo.Abp.Minify\Volo.Abp.Minify.csproj" />
<ProjectReference Include="..\Volo.Abp.AspNetCore.Bundling\Volo.Abp.AspNetCore.Bundling.csproj" />
</ItemGroup>
</Project>

4
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/AbpAspNetCoreMvcUiBundlingModule.cs

@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.Bundling.Styles;
@ -21,8 +22,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
[DependsOn(
typeof(AbpAspNetCoreMvcUiBootstrapModule),
typeof(AbpMinifyModule),
typeof(AbpAspNetCoreMvcUiBundlingAbstractionsModule)
typeof(AbpAspNetCoreBundlingModule)
)]
public class AbpAspNetCoreMvcUiBundlingModule : AbpModule
{

233
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/BundleManager.cs

@ -9,6 +9,10 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Bundling.Scripts;
using Volo.Abp.AspNetCore.Bundling.Styles;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles;
using Volo.Abp.AspNetCore.Mvc.UI.Resources;
@ -17,162 +21,47 @@ using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
public class BundleManager : IBundleManager, ITransientDependency
public class BundleManager : BundleManagerBase, ITransientDependency
{
public ILogger<BundleManager> Logger { get; set; }
protected readonly AbpBundlingOptions Options;
protected readonly AbpBundleContributorOptions ContributorOptions;
protected readonly IWebHostEnvironment HostingEnvironment;
protected readonly IScriptBundler ScriptBundler;
protected readonly IStyleBundler StyleBundler;
protected readonly IServiceProvider ServiceProvider;
protected readonly IDynamicFileProvider DynamicFileProvider;
protected readonly IBundleCache BundleCache;
protected readonly IWebRequestResources RequestResources;
public BundleManager(
IOptions<AbpBundlingOptions> options,
IOptions<AbpBundleContributorOptions> contributorOptions,
IScriptBundler scriptBundler,
IScriptBundler scriptBundler,
IStyleBundler styleBundler,
IWebHostEnvironment hostingEnvironment,
IServiceProvider serviceProvider,
IDynamicFileProvider dynamicFileProvider,
IBundleCache bundleCache,
IWebRequestResources requestResources)
IWebHostEnvironment hostingEnvironment,
IWebRequestResources requestResources) : base(
options,
contributorOptions,
scriptBundler,
styleBundler,
serviceProvider,
dynamicFileProvider,
bundleCache)
{
Options = options.Value;
ContributorOptions = contributorOptions.Value;
HostingEnvironment = hostingEnvironment;
ScriptBundler = scriptBundler;
ServiceProvider = serviceProvider;
DynamicFileProvider = dynamicFileProvider;
BundleCache = bundleCache;
RequestResources = requestResources;
StyleBundler = styleBundler;
Logger = NullLogger<BundleManager>.Instance;
}
public virtual async Task<IReadOnlyList<BundleFile>> GetStyleBundleFilesAsync(string bundleName)
{
return await GetBundleFilesAsync(Options.StyleBundles, bundleName, StyleBundler);
}
public virtual async Task<IReadOnlyList<BundleFile>> GetScriptBundleFilesAsync(string bundleName)
{
return await GetBundleFilesAsync(Options.ScriptBundles, bundleName, ScriptBundler);
}
protected virtual async Task<IReadOnlyList<BundleFile>> GetBundleFilesAsync(BundleConfigurationCollection bundles, string bundleName, IBundler bundler)
{
var files = new List<BundleFile>();
var contributors = GetContributors(bundles, bundleName);
var bundleFiles = RequestResources.TryAdd(await GetBundleFilesAsync(contributors));
var dynamicResources = RequestResources.TryAdd(await GetDynamicResourcesAsync(contributors));
if (!IsBundlingEnabled())
{
return bundleFiles.Union(dynamicResources).ToImmutableList();
}
var localBundleFiles = new List<string>();
foreach (var bundleFile in bundleFiles)
{
if (!bundleFile.IsExternalFile)
{
localBundleFiles.Add(bundleFile.FileName);
}
else
{
if (localBundleFiles.Count != 0)
{
files.AddRange(AddToBundleCache(bundleName, bundler, localBundleFiles).Files);
localBundleFiles.Clear();
}
files.Add(bundleFile);
}
}
if (localBundleFiles.Count != 0)
{
files.AddRange(AddToBundleCache(bundleName, bundler, localBundleFiles).Files);
}
return files.Union(dynamicResources).ToImmutableList();
}
private BundleCacheItem AddToBundleCache(string bundleName, IBundler bundler, List<string> bundleFiles)
{
var bundleRelativePath =
Options.BundleFolderName.EnsureEndsWith('/') +
bundleName + "." + bundleFiles.JoinAsString("|").ToMd5() + "." + bundler.FileExtension;
return BundleCache.GetOrAdd(bundleRelativePath, () =>
{
var cacheValue = new BundleCacheItem(
new List<BundleFile>
{
new BundleFile("/" + bundleRelativePath)
}
);
WatchChanges(cacheValue, bundleFiles, bundleRelativePath);
protected IWebHostEnvironment HostingEnvironment { get; }
var bundleResult = bundler.Bundle(
new BundlerContext(
bundleRelativePath,
bundleFiles,
IsMinficationEnabled()
)
);
protected IWebRequestResources RequestResources { get; }
SaveBundleResult(bundleRelativePath, bundleResult);
return cacheValue;
});
}
private void WatchChanges(BundleCacheItem cacheValue, List<string> files, string bundleRelativePath)
protected async override Task<List<BundleFile>> GetBundleFilesAsync(List<IBundleContributor> contributors)
{
lock (cacheValue.WatchDisposeHandles)
{
foreach (var file in files)
{
var watchDisposeHandle = HostingEnvironment.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);
}
}
return RequestResources.TryAdd(await base.GetBundleFilesAsync(contributors));
}
protected virtual void SaveBundleResult(string bundleRelativePath, BundleResult bundleResult)
protected async override Task<List<BundleFile>> GetDynamicResourcesAsync(List<IBundleContributor> contributors)
{
var fileName = bundleRelativePath.Substring(bundleRelativePath.IndexOf('/') + 1);
DynamicFileProvider.AddOrUpdate(
new InMemoryFileInfo(
"/wwwroot/" + bundleRelativePath, //TODO: get rid of wwwroot!
Encoding.UTF8.GetBytes(bundleResult.Content),
fileName
)
);
return RequestResources.TryAdd(await base.GetDynamicResourcesAsync(contributors));
}
public virtual bool IsBundlingEnabled()
public override bool IsBundlingEnabled()
{
switch (Options.Mode)
{
@ -188,7 +77,7 @@ public class BundleManager : IBundleManager, ITransientDependency
}
}
protected virtual bool IsMinficationEnabled()
protected override bool IsMinficationEnabled()
{
switch (Options.Mode)
{
@ -204,78 +93,8 @@ public class BundleManager : IBundleManager, ITransientDependency
}
}
protected async Task<List<BundleFile>> GetBundleFilesAsync(List<IBundleContributor> contributors)
{
var context = CreateBundleConfigurationContext();
foreach (var contributor in contributors)
{
await contributor.PreConfigureBundleAsync(context);
}
foreach (var contributor in contributors)
{
await contributor.ConfigureBundleAsync(context);
}
foreach (var contributor in contributors)
{
await contributor.PostConfigureBundleAsync(context);
}
return context.Files;
}
protected virtual async Task<List<BundleFile>> GetDynamicResourcesAsync(List<IBundleContributor> contributors)
{
var context = CreateBundleConfigurationContext();
foreach (var contributor in contributors)
{
await contributor.ConfigureDynamicResourcesAsync(context);
}
return context.Files;
}
protected virtual BundleConfigurationContext CreateBundleConfigurationContext()
{
return new BundleConfigurationContext(ServiceProvider, HostingEnvironment.WebRootFileProvider, Options.Parameters);
}
protected virtual List<IBundleContributor> GetContributors(BundleConfigurationCollection bundles, string bundleName)
{
var contributors = new List<IBundleContributor>();
AddContributorsWithBaseBundles(contributors, bundles, bundleName);
for (var i = 0; i < contributors.Count; ++i)
{
var extensions = ContributorOptions.Extensions(contributors[i].GetType()).GetAll();
if (extensions.Count > 0)
{
contributors.InsertRange(i + 1, extensions);
i += extensions.Count;
}
}
return contributors;
}
protected virtual void AddContributorsWithBaseBundles(List<IBundleContributor> contributors, BundleConfigurationCollection bundles, string bundleName)
protected override IFileProvider GetFileProvider()
{
var bundleConfiguration = bundles.Get(bundleName);
foreach (var baseBundleName in bundleConfiguration.BaseBundles)
{
AddContributorsWithBaseBundles(contributors, bundles, baseBundleName); //Recursive call
}
var selfContributors = bundleConfiguration.Contributors.GetAll();
if (selfContributors.Any())
{
contributors.AddRange(selfContributors);
}
return HostingEnvironment.WebRootFileProvider;
}
}
}

25
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/MvcUiBundlerBase.cs

@ -0,0 +1,25 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.Minify;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling;
public abstract class MvcUiBundlerBase : BundlerBase
{
protected IWebHostEnvironment WebHostingEnvironment { get; }
protected MvcUiBundlerBase(
IWebHostEnvironment webHostingEnvironment,
IMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions) : base(minifier, bundlingOptions)
{
WebHostingEnvironment = webHostingEnvironment;
}
protected override IFileInfo FindFileInfo(string file)
{
return WebHostingEnvironment.WebRootFileProvider.GetFileInfo(file);
}
}

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Scripts/IScriptBundler.cs

@ -1,6 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts;
public interface IScriptBundler : IBundler
{
}

8
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Scripts/ScriptBundler.cs

@ -1,20 +1,22 @@
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Bundling.Scripts;
using Volo.Abp.Minify.Scripts;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts;
public class ScriptBundler : BundlerBase, IScriptBundler
public class ScriptBundler : MvcUiBundlerBase, IScriptBundler
{
public override string FileExtension => "js";
public ScriptBundler(
IWebHostEnvironment hostEnvironment,
IWebHostEnvironment hostingEnvironment,
IJavascriptMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions)
: base(
hostEnvironment,
hostingEnvironment,
minifier,
bundlingOptions)
{

6
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/IStyleBundler.cs

@ -1,6 +0,0 @@
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles;
public interface IStyleBundler : IBundler
{
}

11
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/Styles/StyleBundler.cs

@ -2,27 +2,28 @@ using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Bundling.Styles;
using Volo.Abp.Bundling.Styles;
using Volo.Abp.Minify.Styles;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles;
public class StyleBundler : BundlerBase, IStyleBundler
public class StyleBundler : MvcUiBundlerBase, IStyleBundler
{
private readonly IWebHostEnvironment _hostingEnvironment;
public override string FileExtension => "css";
public StyleBundler(
IWebHostEnvironment hostEnvironment,
IWebHostEnvironment hostingEnvironment,
ICssMinifier minifier,
IOptions<AbpBundlingOptions> bundlingOptions)
: base(
hostEnvironment,
hostingEnvironment,
minifier,
bundlingOptions)
{
_hostingEnvironment = hostEnvironment;
_hostingEnvironment = hostingEnvironment;
}
public string GetAbsolutePath(string relativePath)

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperResourceService.cs

@ -10,6 +10,7 @@ using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers;

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperScriptService.cs

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers;

1
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/TagHelpers/AbpTagHelperStyleService.cs

@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.Bundling;
using Volo.Abp.AspNetCore.Security;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers;

2
nupkg/common.ps1

@ -99,6 +99,7 @@ $projects = (
"framework/src/Volo.Abp.AspNetCore.Authentication.OpenIdConnect",
"framework/src/Volo.Abp.AspNetCore.Abstractions",
"framework/src/Volo.Abp.AspNetCore",
"framework/src/Volo.Abp.AspNetCore.Bundling",
"framework/src/Volo.Abp.AspNetCore.Mvc.Dapr",
"framework/src/Volo.Abp.AspNetCore.Mvc.Dapr.EventBus",
"framework/src/Volo.Abp.AspNetCore.Components",
@ -111,6 +112,7 @@ $projects = (
"framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Bundling",
"framework/src/Volo.Abp.AspNetCore.Components.Server",
"framework/src/Volo.Abp.AspNetCore.Components.Server.Theming",
"framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Bundling",
"framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming",
"framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.Bundling",
"framework/src/Volo.Abp.AspNetCore.MultiTenancy",

Loading…
Cancel
Save