diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 1ad283ed78..c24dedae62 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -45,7 +45,7 @@ Here, is the list of all available commands before explaining their details: * **`login`**: Authenticates on your computer with your [abp.io](https://abp.io/) username and password. * **`login-info`**: Shows the current user's login information. * **`logout`**: Logouts from your computer if you've authenticated before. -* **`bundle`**: Generates script and style references for an ABP Blazor project. +* **`bundle`**: Generates script and style references for ABP Blazor and MAUI Blazor project. * **`install-libs`**: Install NPM Packages for MVC / Razor Pages and Blazor Server UI types. ### help @@ -531,7 +531,7 @@ abp logout ### bundle -This command generates script and style references for an ABP Blazor WebAssembly project and updates the **index.html** file. It helps developers to manage dependencies required by ABP modules easily. In order ```bundle``` command to work, its **executing directory** or passed ```--working-directory``` parameter's directory must contain a Blazor project file(*.csproj). +This command generates script and style references for ABP Blazor WebAssembly and MAUI Blazor project and updates the **index.html** file. It helps developers to manage dependencies required by ABP modules easily. In order ```bundle``` command to work, its **executing directory** or passed ```--working-directory``` parameter's directory must contain a Blazor or MAUI Blazor project file(*.csproj). Usage: @@ -543,8 +543,11 @@ abp bundle [options] * ```--working-directory``` or ```-wd```: Specifies the working directory. This option is useful when executing directory doesn't contain a Blazor project file. * ```--force``` or ```-f```: Forces to build project before generating references. +* ```--project-type``` or ```-t```: Specifies the project type. Default type is `webassembly`. Available types: + * `webassembly` + * `maui-blazor` -`bundle` command reads the `appsettings.json` file inside the Blazor project for bundling options. For more details about managing style and script references in Blazor apps, see [Managing Global Scripts & Styles](UI/Blazor/Global-Scripts-Styles.md) +`bundle` command reads the `appsettings.json` file inside the Blazor and MAUI Blazor project for bundling options. For more details about managing style and script references in Blazor or MAUI Blazor apps, see [Managing Global Scripts & Styles](UI/Blazor/Global-Scripts-Styles.md) ### install-libs diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md index 77ed762bfd..58aec193a0 100644 --- a/docs/zh-Hans/CLI.md +++ b/docs/zh-Hans/CLI.md @@ -42,6 +42,7 @@ dotnet tool update -g Volo.Abp.Cli * **`login`**: 使用你在[abp.io](https://abp.io/)的用户名和密码在你的计算机上认证. * **`login-info`**: 展示当前登录用户信息. * **`logout`**: 在你的计算机注销认证. +* **`bundle`**: 为 ABP Blazor 和 MAUI Blazor 项目生成引用的脚本和样式. * **`install-libs`**: 为 MVC / Razor Pages 和 Blazor Server UI 类型安装NPM包. ### help @@ -432,6 +433,26 @@ abp login-info abp logout ``` +### bundle + +这个命令为ABP Blazor WebAssembly 和 MAUI Blazor 项目生成引用的脚本和样式并且更新 **index.html** 文件, 它帮助开发者轻松的管理ABP模块的依赖. 为了使 ```bundle``` 命令工作, 它的**执行目录**或者传递 ```--working-directory``` 参数的目录必须包含Blazor或MAUI Blazor项目文件(*.csproj) + +用法: + +````bash +abp bundle [options] +```` + +#### Options + +* ```--working-directory``` 或 ```-wd```: 指定当前执行目录, 这个命令在当前目录不包含项目文件时非常有用. +* ```--force``` 或 ```-f```: 在生成引用之前强制构建项目. +* ```--project-type``` 或 ```-t```: 指定项目类型. 默认类型是 `webassembly`. 可用的类型有: + * `webassembly` + * `maui-blazor` + +`bundle` command reads the `appsettings.json` file inside the Blazor and MAUI Blazor project for bundling options. For more details about managing style and script references in Blazor or MAUI Blazor apps, see [Managing Global Scripts & Styles](UI/Blazor/Global-Scripts-Styles.md) + ### install-libs 为 MVC / Razor Pages 和 Blazor Server UI 类型安装NPM包, 它的 **执行目录** 或者传递的 ```--working-directory``` 目录必须包含一个项目文件(*.csproj). diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundleOptions.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundleOptions.cs index 93ec1bf884..c9ec97e3a8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundleOptions.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundleOptions.cs @@ -15,6 +15,9 @@ public class BundleOptions [NotNull] public string ProjectFileName { get; set; } + + [NotNull] + public string ProjectType { get; set; } public bool Minify { get; set; } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlerBase.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlerBase.cs index de57a20d83..581cf9b8fc 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlerBase.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlerBase.cs @@ -35,7 +35,7 @@ public abstract class BundlerBase : IBundler, ITransientDependency var bundleFileDefinitions = context.BundleDefinitions.Where(t => t.ExcludeFromBundle == false).ToList(); var fileDefinitionsExcludingFromBundle = context.BundleDefinitions.Where(t => t.ExcludeFromBundle).ToList(); - var bundledContent = BundleFiles(options, bundleFileDefinitions); + var bundledContent = options.ProjectType == BundlingConsts.WebAssembly? BundleWebAssemblyFiles(options, bundleFileDefinitions) : BundleMauiBlazorFiles(options, bundleFileDefinitions); File.WriteAllText(bundleFilePath, bundledContent); return GenerateDefinition(bundleFilePath,fileDefinitionsExcludingFromBundle); @@ -59,7 +59,7 @@ public abstract class BundlerBase : IBundler, ITransientDependency return false; } - private string BundleFiles(BundleOptions options, List bundleDefinitions) + private string BundleWebAssemblyFiles(BundleOptions options, List bundleDefinitions) { var staticAssetsFilePath = Path.Combine(options.Directory, "bin", "Debug", options.FrameworkVersion, $"{options.ProjectFileName}.staticwebassets.runtime.json"); @@ -99,7 +99,7 @@ public abstract class BundlerBase : IBundler, ITransientDependency var fileName = definition.Source.Substring(slashIndex + 1, definition.Source.Length - slashIndex - 1); var filePath = - Path.Combine(PathHelper.GetFrameworkFolderPath(options.Directory, options.FrameworkVersion), + Path.Combine(PathHelper.GetWebAssemblyFrameworkFolderPath(options.Directory, options.FrameworkVersion), fileName); content = GetFileContent(filePath, false); } @@ -119,6 +119,29 @@ public abstract class BundlerBase : IBundler, ITransientDependency } } + private string BundleMauiBlazorFiles(BundleOptions options, List bundleDefinitions) + { + var builder = new StringBuilder(); + foreach (var definition in bundleDefinitions) + { + var filePath = Path.Combine(definition.Source.Split('/')); + + var fileFullPath = Directory.GetFiles(options.Directory, string.Empty, SearchOption.AllDirectories).FirstOrDefault(x => x.EndsWith(filePath)); + if(fileFullPath == null) + { + throw new AbpException("Not found: " + definition.Source); + } + + var content = GetFileContent(fileFullPath, options.Minify); + content = ProcessBeforeAddingToTheBundle(definition.Source, Path.Combine(options.Directory, "wwwroot"), + content); + + builder.AppendLine(content); + } + + return builder.ToString(); + } + private string GetFileContent(string filePath, bool minify) { var content = File.ReadAllText(filePath); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingConsts.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingConsts.cs index 9b74d3e629..74c602461a 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingConsts.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingConsts.cs @@ -7,4 +7,7 @@ internal static class BundlingConsts internal const string ScriptPlaceholderStart = ""; internal const string ScriptPlaceholderEnd = ""; internal const string SupportedWebAssemblyProjectType = "Microsoft.NET.Sdk.BlazorWebAssembly"; + internal const string SupportedMauiBlazorProjectType = "Microsoft.NET.Sdk.Razor"; + internal const string WebAssembly = "webassembly"; + internal const string MauiBlazor = "maui-blazor"; } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingService.cs index 5f6f4a392d..7580b7e5be 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/BundlingService.cs @@ -29,7 +29,7 @@ public class BundlingService : IBundlingService, ITransientDependency public IStyleBundler StyleBundler { get; set; } public IConfigReader ConfigReader { get; set; } - public async Task BundleAsync(string directory, bool forceBuild) + public async Task BundleAsync(string directory, bool forceBuild, string projectType = BundlingConsts.WebAssembly) { var projectFiles = Directory.GetFiles(directory, "*.csproj"); if (!projectFiles.Any()) @@ -40,9 +40,9 @@ public class BundlingService : IBundlingService, ITransientDependency var projectFilePath = projectFiles[0]; - CheckProjectIsSupportedType(projectFilePath); + CheckProjectIsSupportedType(projectFilePath, projectType); - var config = ConfigReader.Read(PathHelper.GetWwwRootPath(directory)); + var config = projectType == BundlingConsts.WebAssembly? ConfigReader.Read(PathHelper.GetWwwRootPath(directory)): ConfigReader.Read(directory); var bundleConfig = config.Bundle; if (forceBuild) @@ -55,9 +55,9 @@ public class BundlingService : IBundlingService, ITransientDependency DotNetProjectBuilder.BuildProjects(projects, string.Empty); } - var frameworkVersion = GetTargetFrameworkVersion(projectFilePath); + var frameworkVersion = GetTargetFrameworkVersion(projectFilePath, projectType); var projectName = Path.GetFileNameWithoutExtension(projectFilePath); - var assemblyFilePath = PathHelper.GetAssemblyFilePath(directory, frameworkVersion, projectName); + var assemblyFilePath = projectType == BundlingConsts.WebAssembly? PathHelper.GetWebAssemblyFilePath(directory, frameworkVersion, projectName) : PathHelper.GetMauiBlazorAssemblyFilePath(directory, projectName); var startupModule = GetStartupModule(assemblyFilePath); var bundleDefinitions = new List(); @@ -65,7 +65,7 @@ public class BundlingService : IBundlingService, ITransientDependency bundleDefinitions = bundleDefinitions.OrderByDescending(t => t.Level).ToList(); var styleContext = GetStyleContext(bundleDefinitions, bundleConfig.Parameters); - var scriptContext = GetScriptContext(bundleDefinitions, bundleConfig.Parameters); + var scriptContext = GetScriptContext(bundleDefinitions, bundleConfig.Parameters, projectType); string styleDefinitions; string scriptDefinitions; @@ -77,7 +77,8 @@ public class BundlingService : IBundlingService, ITransientDependency FrameworkVersion = frameworkVersion, ProjectFileName = projectName, BundleName = bundleConfig.Name.IsNullOrEmpty() ? "global" : bundleConfig.Name, - Minify = bundleConfig.Mode == BundlingMode.BundleAndMinify + Minify = bundleConfig.Mode == BundlingMode.BundleAndMinify, + ProjectType = projectType }; Logger.LogInformation("Generating style bundle..."); @@ -101,17 +102,20 @@ public class BundlingService : IBundlingService, ITransientDependency } private BundleContext GetScriptContext(List bundleDefinitions, - BundleParameterDictionary parameters) + BundleParameterDictionary parameters, string projectType) { var scriptContext = new BundleContext { Parameters = parameters }; - scriptContext.BundleDefinitions.AddIfNotContains( - x => x.Source == "_framework/blazor.webassembly.js", - () => new BundleDefinition { Source = "_framework/blazor.webassembly.js" }); - + if (projectType == BundlingConsts.WebAssembly) + { + scriptContext.BundleDefinitions.AddIfNotContains( + x => x.Source == "_framework/blazor.webassembly.js", + () => new BundleDefinition { Source = "_framework/blazor.webassembly.js" }); + } + foreach (var bundleDefinition in bundleDefinitions) { var contributor = CreateContributorInstance(bundleDefinition.BundleContributorType); @@ -283,24 +287,41 @@ public class BundlingService : IBundlingService, ITransientDependency .SingleOrDefault(AbpModule.IsAbpModule); } - private string GetTargetFrameworkVersion(string projectFilePath) + private string GetTargetFrameworkVersion(string projectFilePath, string projectType) { var document = new XmlDocument(); document.Load(projectFilePath); - return document.SelectSingleNode("//TargetFramework").InnerText; + return projectType switch { + BundlingConsts.WebAssembly => document.SelectSingleNode("//TargetFramework").InnerText, + BundlingConsts.MauiBlazor => document.SelectNodes("//TargetFrameworks")[0].InnerText, + _ => null + }; } - private void CheckProjectIsSupportedType(string projectFilePath) + private void CheckProjectIsSupportedType(string projectFilePath, string projectType) { var document = new XmlDocument(); document.Load(projectFilePath); var sdk = document.DocumentElement.GetAttribute("Sdk"); - if (sdk != BundlingConsts.SupportedWebAssemblyProjectType) + + switch (projectType) { - throw new BundlingException( - $"Unsupported project type. Project type must be {BundlingConsts.SupportedWebAssemblyProjectType}."); + case BundlingConsts.WebAssembly: + if (sdk != BundlingConsts.SupportedWebAssemblyProjectType) + { + throw new BundlingException( + $"Unsupported project type. Project type must be {BundlingConsts.SupportedWebAssemblyProjectType}."); + } + break; + case BundlingConsts.MauiBlazor: + if (sdk != BundlingConsts.SupportedMauiBlazorProjectType) + { + throw new BundlingException( + $"Unsupported project type. Project type must be {BundlingConsts.SupportedMauiBlazorProjectType}."); + } + break; } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/IBundlingService.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/IBundlingService.cs index e2ebfee273..12dfac204e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/IBundlingService.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/IBundlingService.cs @@ -4,5 +4,5 @@ namespace Volo.Abp.Cli.Bundling; public interface IBundlingService { - Task BundleAsync(string directory, bool forceBuild); + Task BundleAsync(string directory, bool forceBuild, string projectType = BundlingConsts.WebAssembly); } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/PathHelper.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/PathHelper.cs index 9fbe074aec..da2bebbf94 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/PathHelper.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Bundling/PathHelper.cs @@ -1,20 +1,26 @@ using System.IO; +using System.Linq; namespace Volo.Abp.Cli.Bundling; internal static class PathHelper { - internal static string GetFrameworkFolderPath(string projectDirectory, string frameworkVersion) + internal static string GetWebAssemblyFrameworkFolderPath(string projectDirectory, string frameworkVersion) { return Path.Combine(projectDirectory, "bin", "Debug", frameworkVersion, "wwwroot", "_framework"); ; } - internal static string GetAssemblyFilePath(string directory, string frameworkVersion, string projectFileName) + internal static string GetWebAssemblyFilePath(string directory, string frameworkVersion, string projectFileName) { - var outputDirectory = GetFrameworkFolderPath(directory, frameworkVersion); + var outputDirectory = GetWebAssemblyFrameworkFolderPath(directory, frameworkVersion); return Path.Combine(outputDirectory, projectFileName + ".dll"); } + internal static string GetMauiBlazorAssemblyFilePath(string directory, string projectFileName) + { + return Directory.GetFiles(directory, "*.dll", SearchOption.AllDirectories).First(f => !f.Contains("android") && f.EndsWith(projectFileName + ".dll")); + } + internal static string GetWwwRootPath(string directory) { return Path.Combine(directory, "wwwroot"); diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BundleCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BundleCommand.cs index e758d22dd3..9e3057b07e 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BundleCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/BundleCommand.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Volo.Abp.Cli.Args; using Volo.Abp.Cli.Bundling; +using Volo.Abp.Cli.Utils; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Cli.Commands; @@ -29,7 +30,8 @@ public class BundleCommand : IConsoleCommand, ITransientDependency var forceBuild = commandLineArgs.Options.ContainsKey(Options.ForceBuild.Short) || commandLineArgs.Options.ContainsKey(Options.ForceBuild.Long); - + + var projectType = GetProjectType(commandLineArgs); if (!Directory.Exists(workingDirectory)) { @@ -42,7 +44,7 @@ public class BundleCommand : IConsoleCommand, ITransientDependency try { - await BundlingService.BundleAsync(workingDirectory, forceBuild); + await BundlingService.BundleAsync(workingDirectory, forceBuild, projectType); } catch (BundlingException ex) { @@ -68,11 +70,24 @@ public class BundleCommand : IConsoleCommand, ITransientDependency sb.AppendLine(""); sb.AppendLine("-wd|--working-directory (default: empty)"); sb.AppendLine("-f | --force (default: false)"); + sb.AppendLine("-t | --project-type (default: webassembly)"); sb.AppendLine(""); sb.AppendLine("See the documentation for more info: https://docs.abp.io/en/abp/latest/CLI"); return sb.ToString(); } + + private string GetProjectType(CommandLineArgs commandLineArgs) + { + var projectType = commandLineArgs.Options.GetOrNull(Options.ProjectType.Short, Options.ProjectType.Long); + projectType ??= BundlingConsts.WebAssembly; + + return projectType.ToLower() switch { + "webassembly" => BundlingConsts.WebAssembly, + "maui-blazor" => BundlingConsts.MauiBlazor, + _ => throw new CliUsageException(ExceptionMessageHelper.GetInvalidOptionExceptionMessage("Project Type")) + }; + } public static class Options { @@ -82,6 +97,12 @@ public class BundleCommand : IConsoleCommand, ITransientDependency public const string Long = "working-directory"; } + public static class ProjectType + { + public const string Short = "t"; + public const string Long = "project-type"; + } + public static class ForceBuild { public const string Short = "f";