mirror of https://github.com/abpframework/abp.git
12 changed files with 437 additions and 0 deletions
@ -0,0 +1,18 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Bundling; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme |
|||
{ |
|||
public class BundleContributer : IBundleContributer |
|||
{ |
|||
public void AddScripts(List<string> scripts) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void AddStyles(List<string> styles) |
|||
{ |
|||
styles.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/libs/abp/css/theme.css"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Bundling; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Theming |
|||
{ |
|||
public class BundleContributer : IBundleContributer |
|||
{ |
|||
public void AddScripts(List<string> scripts) |
|||
{ |
|||
|
|||
} |
|||
|
|||
public void AddStyles(List<string> styles) |
|||
{ |
|||
styles.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/libs/bootstrap/css/bootstrap.css"); |
|||
styles.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/libs/fontawesome/css/all.css"); |
|||
styles.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.WebAssembly.Theming/libs/flag-icon/css/flag-icon.css"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Bundling; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly |
|||
{ |
|||
public class BundleContributer : IBundleContributer |
|||
{ |
|||
public void AddScripts(List<string> scripts) |
|||
{ |
|||
scripts.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.WebAssembly/libs/abp/js/abp.js"); |
|||
} |
|||
|
|||
public void AddStyles(List<string> styles) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Bundling; |
|||
|
|||
namespace Volo.Abp.BlazoriseUI |
|||
{ |
|||
public class BundleContributer : IBundleContributer |
|||
{ |
|||
public void AddScripts(List<string> scripts) |
|||
{ |
|||
scripts.AddIfNotContains("_content/Blazorise/blazorise.js"); |
|||
scripts.AddIfNotContains("_content/Blazorise.Bootstrap/blazorise.bootstrap.js"); |
|||
} |
|||
|
|||
public void AddStyles(List<string> styles) |
|||
{ |
|||
styles.AddIfNotContains("_content/Blazorise/blazorise.css"); |
|||
styles.AddIfNotContains("_content/Blazorise.Bootstrap/blazorise.bootstrap.css"); |
|||
styles.AddIfNotContains("_content/Blazorise.Snackbar/blazorise.snackbar.css"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Cli.Bundling |
|||
{ |
|||
internal class BundleDefinition |
|||
{ |
|||
public int Level { get; set; } |
|||
public Type BundleContributerType { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Cli.Bundling |
|||
{ |
|||
public class BundlingException : Exception |
|||
{ |
|||
public BundlingException(string message) : base(message) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,224 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Xml; |
|||
using Volo.Abp.Bundling; |
|||
using Volo.Abp.Cli.Build; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.Cli.Bundling |
|||
{ |
|||
public class BundlingService : IBundlingService, ITransientDependency |
|||
{ |
|||
const string StylePlaceholderStart = "<!--ABP:Styles-->"; |
|||
const string StylePlaceholderEnd = "<!--/ABP:Styles-->"; |
|||
const string ScriptPlaceholderStart = "<!--ABP:Scripts-->"; |
|||
const string ScriptPlaceholderEnd = "<!--/ABP:Scripts-->"; |
|||
const string SupportedWebAssemblyProjectType = "Microsoft.NET.Sdk.BlazorWebAssembly"; |
|||
|
|||
protected IDotNetProjectBuilder DotNetProjectBuilder { get; set; } |
|||
protected ILogger<BundlingService> Logger { get; set; } |
|||
|
|||
public async Task BundleAsync(string directory, bool forceBuild) |
|||
{ |
|||
var projectFiles = Directory.GetFiles(directory, "*.csproj"); |
|||
if (!projectFiles.Any()) |
|||
{ |
|||
throw new BundlingException("No project file found in the directory"); |
|||
} |
|||
|
|||
var projectFilePath = projectFiles[0]; |
|||
|
|||
if (forceBuild) |
|||
{ |
|||
var projects = new List<DotNetProjectInfo>() |
|||
{ |
|||
new DotNetProjectInfo(string.Empty, projectFilePath, true) |
|||
}; |
|||
Logger.LogInformation("Build starting..."); |
|||
DotNetProjectBuilder.Build(projects, string.Empty); |
|||
Logger.LogInformation("Build completed..."); |
|||
} |
|||
|
|||
var frameworkVersion = GetTargetFrameworkVersion(projectFilePath); |
|||
var assemblyFilePath = GetAssemblyFilePath(directory, frameworkVersion, Path.GetFileNameWithoutExtension(projectFilePath)); |
|||
var startupModule = GetStartupModule(assemblyFilePath); |
|||
|
|||
var bundleDefinitions = new List<BundleDefinition>(); |
|||
FindBundleContributersRecursively(startupModule, 0, bundleDefinitions); |
|||
bundleDefinitions = bundleDefinitions.OrderByDescending(t => t.Level).ToList(); |
|||
|
|||
var styleDefinitons = GenerateStyleDefinitions(bundleDefinitions); |
|||
var scriptDefinitions = GenerateScriptDefinitions(bundleDefinitions); |
|||
|
|||
await UpdateDependenciesInHtmlFileAsync(directory, styleDefinitons, scriptDefinitions); |
|||
} |
|||
|
|||
protected virtual async Task UpdateDependenciesInHtmlFileAsync(string directory, string styleDefinitions, string scriptDefinitions) |
|||
{ |
|||
var htmlFilePath = Path.Combine(directory, "wwwroot", "index.html"); |
|||
if (!File.Exists(htmlFilePath)) |
|||
{ |
|||
throw new BundlingException($"index.html file could not be found in the following path:{htmlFilePath}"); |
|||
} |
|||
|
|||
Encoding fileEncoding; |
|||
string content; |
|||
using (var reader = new StreamReader(htmlFilePath, true)) |
|||
{ |
|||
fileEncoding = reader.CurrentEncoding; |
|||
content = await reader.ReadToEndAsync(); |
|||
} |
|||
|
|||
content = UpdatePlaceholders(content, StylePlaceholderStart, StylePlaceholderEnd, styleDefinitions); |
|||
content = UpdatePlaceholders(content, ScriptPlaceholderStart, ScriptPlaceholderEnd, scriptDefinitions); |
|||
|
|||
using var writer = new StreamWriter(htmlFilePath, false, fileEncoding); |
|||
await writer.WriteAsync(content); |
|||
await writer.FlushAsync(); |
|||
} |
|||
|
|||
private string UpdatePlaceholders(string content, string placeholderStart, string placeholderEnd, string definitions) |
|||
{ |
|||
var placeholderStartIndex = content.IndexOf(placeholderStart); |
|||
var placeholderEndIndex = content.IndexOf(placeholderEnd); |
|||
var updatedContent = content.Remove(placeholderStartIndex, (placeholderEndIndex + placeholderEnd.Length) - placeholderStartIndex); |
|||
return updatedContent.Insert(placeholderStartIndex, definitions); |
|||
} |
|||
|
|||
private string GenerateStyleDefinitions(List<BundleDefinition> bundleDefinitions) |
|||
{ |
|||
var styles = new List<string>(); |
|||
foreach (var bundleDefinition in bundleDefinitions) |
|||
{ |
|||
var contributer = CreateContributerInstance(bundleDefinition.BundleContributerType); |
|||
contributer.AddStyles(styles); |
|||
} |
|||
|
|||
var builder = new StringBuilder(); |
|||
builder.AppendLine($"{StylePlaceholderStart}"); |
|||
foreach (var style in styles) |
|||
{ |
|||
builder.AppendLine($"\t<link href=\"{style}\" rel=\"stylesheet\" />"); |
|||
} |
|||
builder.AppendLine($"\t{StylePlaceholderEnd}"); |
|||
|
|||
return builder.ToString(); |
|||
} |
|||
|
|||
private string GenerateScriptDefinitions(List<BundleDefinition> bundleDefinitions) |
|||
{ |
|||
var scripts = new List<string> |
|||
{ |
|||
"_framework/blazor.webassembly.js" |
|||
}; |
|||
foreach (var bundleDefinition in bundleDefinitions) |
|||
{ |
|||
var contributer = CreateContributerInstance(bundleDefinition.BundleContributerType); |
|||
contributer.AddScripts(scripts); |
|||
} |
|||
|
|||
var builder = new StringBuilder(); |
|||
builder.AppendLine($"{ScriptPlaceholderStart}"); |
|||
foreach (var script in scripts) |
|||
{ |
|||
builder.AppendLine($"\t<script src=\"{script}\"></script>"); |
|||
} |
|||
builder.AppendLine($"\t{ScriptPlaceholderEnd}"); |
|||
|
|||
return builder.ToString(); |
|||
} |
|||
|
|||
private IBundleContributer CreateContributerInstance(Type bundleContributerType) |
|||
{ |
|||
var instance = Activator.CreateInstance(bundleContributerType); |
|||
return instance.As<IBundleContributer>(); |
|||
} |
|||
|
|||
private void FindBundleContributersRecursively(Type module, int level, List<BundleDefinition> bundleDefinitions) |
|||
{ |
|||
var dependencyDescriptors = module |
|||
.GetCustomAttributes() |
|||
.OfType<IDependedTypesProvider>(); |
|||
|
|||
var bundleContributer = module.Assembly.GetTypes().SingleOrDefault(t => t.IsAssignableTo<IBundleContributer>()); |
|||
if (bundleContributer != null) |
|||
{ |
|||
var definition = bundleDefinitions.SingleOrDefault(t => t.BundleContributerType == bundleContributer); |
|||
if (definition != null) |
|||
{ |
|||
if (definition.Level < level) |
|||
{ |
|||
definition.Level = level; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
bundleDefinitions.Add(new BundleDefinition |
|||
{ |
|||
Level = level, |
|||
BundleContributerType = bundleContributer |
|||
}); |
|||
} |
|||
} |
|||
|
|||
foreach (var descriptor in dependencyDescriptors) |
|||
{ |
|||
foreach (var dependedModuleType in descriptor.GetDependedTypes()) |
|||
{ |
|||
FindBundleContributersRecursively(dependedModuleType, level + 1, bundleDefinitions); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private Type GetStartupModule(string assemblyPath) |
|||
{ |
|||
var assembly = Assembly.LoadFrom(assemblyPath); |
|||
return assembly.GetTypes().SingleOrDefault(IsAbpModule); |
|||
|
|||
static bool IsAbpModule(Type type) |
|||
{ |
|||
var typeInfo = type.GetTypeInfo(); |
|||
|
|||
return |
|||
typeInfo.IsClass && |
|||
!typeInfo.IsAbstract && |
|||
!typeInfo.IsGenericType && |
|||
typeof(IAbpModule).GetTypeInfo().IsAssignableFrom(type); |
|||
} |
|||
} |
|||
|
|||
private string GetFrameworkFolderPath(string projectDirectory, string frameworkVersion) |
|||
{ |
|||
return Path.Combine(projectDirectory, "bin", "Debug", frameworkVersion, "wwwroot", "_framework"); ; |
|||
} |
|||
|
|||
private string GetTargetFrameworkVersion(string projectFilePath) |
|||
{ |
|||
var document = new XmlDocument(); |
|||
document.Load(projectFilePath); |
|||
var sdk = document.DocumentElement.GetAttribute("Sdk"); |
|||
if (sdk == SupportedWebAssemblyProjectType) |
|||
{ |
|||
var frameworkVersion = document.SelectSingleNode("//TargetFramework").InnerText; |
|||
return frameworkVersion; |
|||
} |
|||
else |
|||
{ |
|||
throw new BundlingException($"Unsupported project type. Project type must be {SupportedWebAssemblyProjectType}."); |
|||
} |
|||
} |
|||
|
|||
private string GetAssemblyFilePath(string directory, string frameworkVersion, string projectFileName) |
|||
{ |
|||
var outputDirectory = GetFrameworkFolderPath(directory, frameworkVersion); |
|||
return Path.Combine(outputDirectory, projectFileName + ".dll"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Cli.Bundling |
|||
{ |
|||
public interface IBundlingService |
|||
{ |
|||
Task BundleAsync(string directory, bool forceBuild); |
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
using Microsoft.Extensions.Logging; |
|||
using System; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Cli.Args; |
|||
using Volo.Abp.Cli.Bundling; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands |
|||
{ |
|||
public class BundleCommand : IConsoleCommand, ITransientDependency |
|||
{ |
|||
public ILogger<BundleCommand> Logger { get; set; } |
|||
|
|||
public IBundlingService BundlingService { get; set; } |
|||
|
|||
|
|||
public async Task ExecuteAsync(CommandLineArgs commandLineArgs) |
|||
{ |
|||
var workingDirectoryArg = commandLineArgs.Options.GetOrNull( |
|||
Options.WorkingDirectory.Short, |
|||
Options.WorkingDirectory.Long |
|||
); |
|||
|
|||
var workingDirectory = workingDirectoryArg ?? Directory.GetCurrentDirectory(); |
|||
|
|||
var forceBuild = commandLineArgs.Options.ContainsKey(Options.ForceBuild.Short) || |
|||
commandLineArgs.Options.ContainsKey(Options.ForceBuild.Long); |
|||
|
|||
if (!Directory.Exists(workingDirectory)) |
|||
{ |
|||
throw new CliUsageException( |
|||
"Specified directory does not exist." + |
|||
Environment.NewLine + Environment.NewLine + |
|||
GetUsageInfo() |
|||
); |
|||
} |
|||
|
|||
try |
|||
{ |
|||
await BundlingService.BundleAsync(workingDirectory, forceBuild); |
|||
} |
|||
catch (BundlingException ex) |
|||
{ |
|||
Logger.LogError(ex.Message); |
|||
} |
|||
} |
|||
|
|||
public string GetShortDescription() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public string GetUsageInfo() |
|||
{ |
|||
throw new NotImplementedException(); |
|||
} |
|||
|
|||
public static class Options |
|||
{ |
|||
public static class WorkingDirectory |
|||
{ |
|||
public const string Short = "wd"; |
|||
public const string Long = "working-directory"; |
|||
} |
|||
|
|||
public static class ForceBuild |
|||
{ |
|||
public const string Short = "f"; |
|||
public const string Long = "force"; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
|
|||
namespace Volo.Abp.Bundling |
|||
{ |
|||
public interface IBundleContributer |
|||
{ |
|||
void AddScripts(List<string> scripts); |
|||
void AddStyles(List<string> styles); |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.Bundling; |
|||
|
|||
namespace Volo.Abp.Http.Client.IdentityModel.WebAssembly |
|||
{ |
|||
public class BundleContributer : IBundleContributer |
|||
{ |
|||
public void AddScripts(List<string> scripts) |
|||
{ |
|||
scripts.AddIfNotContains("_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"); |
|||
} |
|||
|
|||
public void AddStyles(List<string> styles) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue