mirror of https://github.com/abpframework/abp.git
37 changed files with 471 additions and 121 deletions
@ -1,6 +0,0 @@ |
|||||
[ |
|
||||
{ |
|
||||
"outputFile": "wwwroot/libs/abp/aspnetcore.mvc.ui.theme.shared/datatables/datatables.css", |
|
||||
"inputFile": "wwwroot/libs/abp/aspnetcore.mvc.ui.theme.shared/datatables/datatables.scss" |
|
||||
} |
|
||||
] |
|
||||
@ -1,49 +0,0 @@ |
|||||
{ |
|
||||
"compilers": { |
|
||||
"less": { |
|
||||
"autoPrefix": "", |
|
||||
"cssComb": "none", |
|
||||
"ieCompat": true, |
|
||||
"strictMath": false, |
|
||||
"strictUnits": false, |
|
||||
"relativeUrls": true, |
|
||||
"rootPath": "", |
|
||||
"sourceMapRoot": "", |
|
||||
"sourceMapBasePath": "", |
|
||||
"sourceMap": false |
|
||||
}, |
|
||||
"sass": { |
|
||||
"includePath": "", |
|
||||
"indentType": "space", |
|
||||
"indentWidth": 2, |
|
||||
"outputStyle": "nested", |
|
||||
"Precision": 5, |
|
||||
"relativeUrls": true, |
|
||||
"sourceMapRoot": "", |
|
||||
"sourceMap": false |
|
||||
}, |
|
||||
"stylus": { |
|
||||
"sourceMap": false |
|
||||
}, |
|
||||
"babel": { |
|
||||
"sourceMap": false |
|
||||
}, |
|
||||
"coffeescript": { |
|
||||
"bare": false, |
|
||||
"runtimeMode": "node", |
|
||||
"sourceMap": false |
|
||||
} |
|
||||
}, |
|
||||
"minifiers": { |
|
||||
"css": { |
|
||||
"enabled": true, |
|
||||
"termSemicolons": true, |
|
||||
"gzip": false |
|
||||
}, |
|
||||
"javascript": { |
|
||||
"enabled": true, |
|
||||
"termSemicolons": true, |
|
||||
"gzip": false |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
|
{ |
||||
|
public class BundleResult |
||||
|
{ |
||||
|
public string Content { get; } |
||||
|
|
||||
|
public BundleResult(string content) |
||||
|
{ |
||||
|
Content = content; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,18 +0,0 @@ |
|||||
using System.Collections.Generic; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|
||||
{ |
|
||||
public class Bundler : IBundler, ITransientDependency |
|
||||
{ |
|
||||
public Bundler() |
|
||||
{ |
|
||||
|
|
||||
} |
|
||||
|
|
||||
public string CreateBundle(List<string> files) |
|
||||
{ |
|
||||
return ""; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,53 @@ |
|||||
|
using System.Text; |
||||
|
using Microsoft.Extensions.FileProviders; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Minification; |
||||
|
using Volo.Abp.AspNetCore.VirtualFileSystem; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
|
{ |
||||
|
public abstract class BundlerBase : IBundler, ITransientDependency |
||||
|
{ |
||||
|
protected IHybridWebRootFileProvider WebRootFileProvider { get; } |
||||
|
protected IMinifier Minifier { get; } |
||||
|
|
||||
|
protected BundlerBase(IHybridWebRootFileProvider webRootFileProvider, IMinifier minifier) |
||||
|
{ |
||||
|
WebRootFileProvider = webRootFileProvider; |
||||
|
Minifier = minifier; |
||||
|
} |
||||
|
|
||||
|
public abstract string FileExtension { get; } |
||||
|
|
||||
|
public BundleResult Bundle(IBundlerContext context) |
||||
|
{ |
||||
|
var sb = new StringBuilder(); |
||||
|
|
||||
|
foreach (var file in context.ContentFiles) |
||||
|
{ |
||||
|
sb.AppendLine(GetFileContent(context, file)); |
||||
|
} |
||||
|
|
||||
|
return new BundleResult( |
||||
|
Minifier.Minify(sb.ToString(), context.BundleRelativePath) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
protected virtual string GetFileContent(IBundlerContext context, string file) |
||||
|
{ |
||||
|
return GetFileInfo(context, file).ReadAsString(); |
||||
|
} |
||||
|
|
||||
|
protected virtual IFileInfo GetFileInfo(IBundlerContext context, string file) |
||||
|
{ |
||||
|
var fileInfo = WebRootFileProvider.GetFileInfo(file); |
||||
|
|
||||
|
if (!fileInfo.Exists) |
||||
|
{ |
||||
|
throw new AbpException($"Could not find file '{file}' using {nameof(IHybridWebRootFileProvider)}"); |
||||
|
} |
||||
|
|
||||
|
return fileInfo; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
|
{ |
||||
|
public class BundlerContext : IBundlerContext |
||||
|
{ |
||||
|
public string BundleRelativePath { get; } |
||||
|
|
||||
|
public IReadOnlyList<string> ContentFiles { get; } |
||||
|
|
||||
|
public BundlerContext(string bundleRelativePath, IReadOnlyList<string> contentFiles) |
||||
|
{ |
||||
|
BundleRelativePath = bundleRelativePath; |
||||
|
ContentFiles = contentFiles; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,9 @@ |
|||||
using System.Collections.Generic; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
{ |
{ |
||||
public interface IBundler |
public interface IBundler |
||||
{ |
{ |
||||
string CreateBundle(List<string> files); |
string FileExtension { get; } |
||||
|
|
||||
|
BundleResult Bundle(IBundlerContext context); |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling |
||||
|
{ |
||||
|
public interface IBundlerContext |
||||
|
{ |
||||
|
string BundleRelativePath { get; } |
||||
|
|
||||
|
IReadOnlyList<string> ContentFiles { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts |
||||
|
{ |
||||
|
public interface IScriptBundler : IBundler |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Minification.Scripts; |
||||
|
using Volo.Abp.AspNetCore.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Scripts |
||||
|
{ |
||||
|
public class ScriptBundler : BundlerBase, IScriptBundler |
||||
|
{ |
||||
|
public override string FileExtension => "js"; |
||||
|
|
||||
|
public ScriptBundler(IHybridWebRootFileProvider webRootFileProvider, IJavascriptMinifier minifier) |
||||
|
: base(webRootFileProvider, minifier) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,74 @@ |
|||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles |
||||
|
{ |
||||
|
internal static class CssRelativePath |
||||
|
{ |
||||
|
private static readonly Regex _rxUrl = new Regex(@"url\s*\(\s*([""']?)([^:)]+)\1\s*\)", RegexOptions.IgnoreCase | RegexOptions.Compiled); |
||||
|
|
||||
|
public static string Adjust(string cssFileContents, string absoluteInputFilePath, string absoluteOutputPath) |
||||
|
{ |
||||
|
var matches = _rxUrl.Matches(cssFileContents); |
||||
|
|
||||
|
if (matches.Count <= 0) |
||||
|
{ |
||||
|
return cssFileContents; |
||||
|
} |
||||
|
|
||||
|
var cssDirectoryPath = Path.GetDirectoryName(absoluteInputFilePath); |
||||
|
|
||||
|
foreach (Match match in matches) |
||||
|
{ |
||||
|
string quoteDelimiter = match.Groups[1].Value; //url('') vs url("")
|
||||
|
string relativePathToCss = match.Groups[2].Value; |
||||
|
|
||||
|
// Ignore root relative references
|
||||
|
if (relativePathToCss.StartsWith("/", StringComparison.Ordinal)) |
||||
|
continue; |
||||
|
|
||||
|
//prevent query string from causing error
|
||||
|
var pathAndQuery = relativePathToCss.Split(new[] { '?' }, 2, StringSplitOptions.RemoveEmptyEntries); |
||||
|
var pathOnly = pathAndQuery[0]; |
||||
|
var queryOnly = pathAndQuery.Length == 2 ? pathAndQuery[1] : string.Empty; |
||||
|
|
||||
|
string absolutePath = GetAbsolutePath(cssDirectoryPath, pathOnly); |
||||
|
string serverRelativeUrl = MakeRelative(absoluteOutputPath, absolutePath); |
||||
|
|
||||
|
if (!string.IsNullOrEmpty(queryOnly)) |
||||
|
serverRelativeUrl += "?" + queryOnly; |
||||
|
|
||||
|
string replace = string.Format("url({0}{1}{0})", quoteDelimiter, serverRelativeUrl); |
||||
|
|
||||
|
cssFileContents = cssFileContents.Replace(match.Groups[0].Value, replace); |
||||
|
} |
||||
|
|
||||
|
return cssFileContents; |
||||
|
} |
||||
|
|
||||
|
private static string GetAbsolutePath(string cssFilePath, string pathOnly) |
||||
|
{ |
||||
|
return Path.GetFullPath(Path.Combine(cssFilePath, pathOnly)); |
||||
|
} |
||||
|
|
||||
|
private static readonly string _protocol = "file:///"; |
||||
|
private static string MakeRelative(string baseFile, string file) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(file)) |
||||
|
return file; |
||||
|
|
||||
|
Uri baseUri = new Uri(_protocol + baseFile, UriKind.RelativeOrAbsolute); |
||||
|
Uri fileUri = new Uri(_protocol + file, UriKind.RelativeOrAbsolute); |
||||
|
|
||||
|
if (baseUri.IsAbsoluteUri) |
||||
|
{ |
||||
|
return Uri.UnescapeDataString(baseUri.MakeRelativeUri(fileUri).ToString()); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return baseUri.ToString(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles |
||||
|
{ |
||||
|
public interface IStyleBundler : IBundler |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Minification.Styles; |
||||
|
using Volo.Abp.AspNetCore.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling.Styles |
||||
|
{ |
||||
|
public class StyleBundler : BundlerBase, IStyleBundler |
||||
|
{ |
||||
|
public override string FileExtension => "css"; |
||||
|
|
||||
|
public StyleBundler(IHybridWebRootFileProvider webRootFileProvider, ICssMinifier minifier) |
||||
|
: base(webRootFileProvider, minifier) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
protected override string GetFileContent(IBundlerContext context, string file) |
||||
|
{ |
||||
|
var content = base.GetFileContent(context, file); |
||||
|
return CssRelativePath.Adjust( |
||||
|
content, |
||||
|
WebRootFileProvider.GetAbsolutePath(file), |
||||
|
WebRootFileProvider.GetAbsolutePath(context.BundleRelativePath) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,6 +1,6 @@ |
|||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification |
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification |
||||
{ |
{ |
||||
public interface IJavascriptMinifier |
public interface IMinifier |
||||
{ |
{ |
||||
string Minify(string source, string fileName = null); |
string Minify(string source, string fileName = null); |
||||
} |
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using NUglify; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Minification.Styles; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification.NUglify |
||||
|
{ |
||||
|
public class NUglifyCssMinifier : NUglifyMinifierBase, ICssMinifier |
||||
|
{ |
||||
|
protected override UglifyResult UglifySource(string source, string fileName) |
||||
|
{ |
||||
|
return Uglify.Css(source, fileName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,26 +1,15 @@ |
|||||
using NUglify; |
using NUglify; |
||||
|
using NUglify.JavaScript; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Minification.Scripts; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification.NUglify |
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification.NUglify |
||||
{ |
{ |
||||
public class NUglifyJavascriptMinifier : IJavascriptMinifier, ITransientDependency |
public class NUglifyJavascriptMinifier : NUglifyMinifierBase, IJavascriptMinifier |
||||
{ |
{ |
||||
public string Minify(string source, string fileName = null) |
protected override UglifyResult UglifySource(string source, string fileName) |
||||
{ |
{ |
||||
var result = Uglify.Js(source, fileName); |
return Uglify.Js(source, fileName); |
||||
CheckErrors(result); |
|
||||
return result.Code; |
|
||||
} |
|
||||
|
|
||||
private static void CheckErrors(UglifyResult result) |
|
||||
{ |
|
||||
if (result.HasErrors) |
|
||||
{ |
|
||||
throw new NUglifyException( |
|
||||
"There are some errors on uglifying the given source code!", |
|
||||
result.Errors |
|
||||
); |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using NUglify; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification.NUglify |
||||
|
{ |
||||
|
public abstract class NUglifyMinifierBase : IMinifier, ITransientDependency |
||||
|
{ |
||||
|
private static void CheckErrors(UglifyResult result) |
||||
|
{ |
||||
|
if (result.HasErrors) |
||||
|
{ |
||||
|
throw new NUglifyException( |
||||
|
$"There are some errors on uglifying the given source code!{Environment.NewLine}{result.Errors.Select(err => err.ToString()).JoinAsString(Environment.NewLine)}", |
||||
|
result.Errors |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public string Minify(string source, string fileName = null) |
||||
|
{ |
||||
|
var result = UglifySource(source, fileName); |
||||
|
CheckErrors(result); |
||||
|
return result.Code; |
||||
|
} |
||||
|
|
||||
|
protected abstract UglifyResult UglifySource(string source, string fileName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification.Scripts |
||||
|
{ |
||||
|
public interface IJavascriptMinifier : IMinifier |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Mvc.UI.Minification.Styles |
||||
|
{ |
||||
|
public interface ICssMinifier : IMinifier |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
using System; |
||||
|
using System.IO; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.Extensions.FileProviders; |
||||
|
using Microsoft.Extensions.Primitives; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.VirtualFileSystem |
||||
|
{ |
||||
|
public class HybridWebRootFileProvider : IHybridWebRootFileProvider, ISingletonDependency |
||||
|
{ |
||||
|
private readonly IVirtualFileProvider _virtualFileProvider; |
||||
|
private readonly IFileProvider _fileProvider; |
||||
|
private readonly IHostingEnvironment _hostingEnvironment; |
||||
|
|
||||
|
public HybridWebRootFileProvider(IVirtualFileProvider virtualFileProvider, IHostingEnvironment hostingEnvironment) |
||||
|
{ |
||||
|
_virtualFileProvider = virtualFileProvider; |
||||
|
_hostingEnvironment = hostingEnvironment; |
||||
|
|
||||
|
_fileProvider = CreateHybridProvider(); |
||||
|
} |
||||
|
|
||||
|
public virtual IFileInfo GetFileInfo(string subpath) |
||||
|
{ |
||||
|
return _fileProvider.GetFileInfo("/wwwroot" + subpath); //TODO: Hard-coded "/wwwroot" is not good!
|
||||
|
} |
||||
|
|
||||
|
public virtual IDirectoryContents GetDirectoryContents(string subpath) |
||||
|
{ |
||||
|
return _fileProvider.GetDirectoryContents("/wwwroot" + subpath); |
||||
|
} |
||||
|
|
||||
|
public virtual IChangeToken Watch(string filter) |
||||
|
{ |
||||
|
return _fileProvider.Watch("/wwwroot" + filter); |
||||
|
} |
||||
|
|
||||
|
public string GetAbsolutePath(string relativePath) |
||||
|
{ |
||||
|
return Path.Combine(_hostingEnvironment.ContentRootPath, "wwwroot", relativePath.RemovePreFix("/")); |
||||
|
} |
||||
|
|
||||
|
protected virtual IFileProvider CreateHybridProvider() |
||||
|
{ |
||||
|
return new CompositeFileProvider( |
||||
|
_hostingEnvironment.ContentRootFileProvider, |
||||
|
_virtualFileProvider |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Microsoft.Extensions.FileProviders; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.VirtualFileSystem |
||||
|
{ |
||||
|
public interface IHybridWebRootFileProvider : IFileProvider |
||||
|
{ |
||||
|
string GetAbsolutePath(string relativePath); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System.IO; |
||||
|
|
||||
|
namespace Volo.Abp.IO |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A helper class for Directory operations.
|
||||
|
/// </summary>
|
||||
|
public static class DirectoryHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates a new directory if it does not exists.
|
||||
|
/// </summary>
|
||||
|
/// <param name="directory">Directory to create</param>
|
||||
|
public static void CreateIfNotExists(string directory) |
||||
|
{ |
||||
|
if (!Directory.Exists(directory)) |
||||
|
{ |
||||
|
Directory.CreateDirectory(directory); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
using System.IO; |
||||
|
|
||||
|
namespace Volo.Abp.IO |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A helper class for File operations.
|
||||
|
/// </summary>
|
||||
|
public static class FileHelper |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Checks and deletes given file if it does exists.
|
||||
|
/// </summary>
|
||||
|
/// <param name="filePath">Path of the file</param>
|
||||
|
public static void DeleteIfExists(string filePath) |
||||
|
{ |
||||
|
if (File.Exists(filePath)) |
||||
|
{ |
||||
|
File.Delete(filePath); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue