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 |
|||
{ |
|||
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 |
|||
{ |
|||
public interface IJavascriptMinifier |
|||
public interface IMinifier |
|||
{ |
|||
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.JavaScript; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Minification.Scripts; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
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); |
|||
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 |
|||
); |
|||
} |
|||
return Uglify.Js(source, fileName); |
|||
} |
|||
} |
|||
} |
|||
@ -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