我想在我的web项目LESS文件,并有MVC 4捆绑功能调用到带点库打开少进CSS,然后缩小的结果,并给它的浏览器。
我发现了一个例子ASP.NET网站 (在标题LESS,CoffeeScript中,SCSS,萨斯捆绑)。 这给了我一个LessTransform
类,看起来像这样:
public class LessTransform : IBundleTransform
{
public void Process(BundleContext context, BundleResponse response)
{
response.Content = dotless.Core.Less.Parse(response.Content);
response.ContentType = "text/css";
}
}
而这条线在我的BundleConfig
类:
bundles.Add(new Bundle(
"~/Content/lessTest",
new LessTransform(),
new CssMinify()).Include("~/Content/less/test.less"));
终于我在_Layout.cshtml以下行,在<head>
:
@Styles.Render("~/Content/lessTest")
如果我在调试模式下的网站,这是呈现给浏览器:
<link href="/Content/less/test.less" rel="stylesheet"/>
在.LESS文件中的规则应用,并按照该链接显示,LESS已经被正确地转化为CSS。
但是,如果我把网站变成释放模式,这是呈现出来:
<link href="/Content/less?v=lEs-HID6XUz3s2qkJ35Lvnwwq677wTaIiry6fuX8gz01" rel="stylesheet"/>
在.LESS文件中的规则不适用,因为下面的链接给出了IIS 404错误。
如此看来,一些与捆绑脚麻。 我如何得到这个在释放模式工作,或者我怎么找出究竟是怎么了?
Answer 1:
看来,带点引擎需要知道当前处理的包文件的路径来解决@import路径。 如果你运行你有上面的过程代码中,dotless.Core.Less.Parse的()的结果是,当正在分析的.LESS文件有进口其他不太文件一个空字符串。
这里福斯特的反应会解决这个问题,首先读取导入的文件:
导入文件和带点
更改您的LessTransform文件,如下所示:
public class LessTransform : IBundleTransform
{
public void Process(BundleContext context, BundleResponse bundle)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (bundle == null)
{
throw new ArgumentNullException("bundle");
}
context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies();
var lessParser = new Parser();
ILessEngine lessEngine = CreateLessEngine(lessParser);
var content = new StringBuilder(bundle.Content.Length);
var bundleFiles = new List<FileInfo>();
foreach (var bundleFile in bundle.Files)
{
bundleFiles.Add(bundleFile);
SetCurrentFilePath(lessParser, bundleFile.FullName);
string source = File.ReadAllText(bundleFile.FullName);
content.Append(lessEngine.TransformToCss(source, bundleFile.FullName));
content.AppendLine();
bundleFiles.AddRange(GetFileDependencies(lessParser));
}
if (BundleTable.EnableOptimizations)
{
// include imports in bundle files to register cache dependencies
bundle.Files = bundleFiles.Distinct();
}
bundle.ContentType = "text/css";
bundle.Content = content.ToString();
}
/// <summary>
/// Creates an instance of LESS engine.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
private ILessEngine CreateLessEngine(Parser lessParser)
{
var logger = new AspNetTraceLogger(LogLevel.Debug, new Http());
return new LessEngine(lessParser, logger, true, false);
}
/// <summary>
/// Gets the file dependencies (@imports) of the LESS file being parsed.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
/// <returns>An array of file references to the dependent file references.</returns>
private IEnumerable<FileInfo> GetFileDependencies(Parser lessParser)
{
IPathResolver pathResolver = GetPathResolver(lessParser);
foreach (var importPath in lessParser.Importer.Imports)
{
yield return new FileInfo(pathResolver.GetFullPath(importPath));
}
lessParser.Importer.Imports.Clear();
}
/// <summary>
/// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
private IPathResolver GetPathResolver(Parser lessParser)
{
var importer = lessParser.Importer as Importer;
var fileReader = importer.FileReader as FileReader;
return fileReader.PathResolver;
}
/// <summary>
/// Informs the LESS parser about the path to the currently processed file.
/// This is done by using a custom <see cref="IPathResolver"/> implementation.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
/// <param name="currentFilePath">The path to the currently processed file.</param>
private void SetCurrentFilePath(Parser lessParser, string currentFilePath)
{
var importer = lessParser.Importer as Importer;
if (importer == null)
throw new InvalidOperationException("Unexpected dotless importer type.");
var fileReader = importer.FileReader as FileReader;
if (fileReader == null || !(fileReader.PathResolver is ImportedFilePathResolver))
{
fileReader = new FileReader(new ImportedFilePathResolver(currentFilePath));
importer.FileReader = fileReader;
}
}
}
public class ImportedFilePathResolver : IPathResolver
{
private string currentFileDirectory;
private string currentFilePath;
public ImportedFilePathResolver(string currentFilePath)
{
if (string.IsNullOrEmpty(currentFilePath))
{
throw new ArgumentNullException("currentFilePath");
}
CurrentFilePath = currentFilePath;
}
/// <summary>
/// Gets or sets the path to the currently processed file.
/// </summary>
public string CurrentFilePath
{
get { return currentFilePath; }
set
{
currentFilePath = value;
currentFileDirectory = Path.GetDirectoryName(value);
}
}
/// <summary>
/// Returns the absolute path for the specified improted file path.
/// </summary>
/// <param name="filePath">The imported file path.</param>
public string GetFullPath(string filePath)
{
if (filePath.StartsWith("~"))
{
filePath = VirtualPathUtility.ToAbsolute(filePath);
}
if (filePath.StartsWith("/"))
{
filePath = HostingEnvironment.MapPath(filePath);
}
else if (!Path.IsPathRooted(filePath))
{
filePath = Path.GetFullPath(Path.Combine(currentFileDirectory, filePath));
}
return filePath;
}
}
Answer 2:
作为补充, 接受的答案 ,我创建了一个LessBundle类,它是StyleBundle类的少eqivalent。
LessBundle.cs代码是:
using System.Web.Optimization;
namespace MyProject
{
public class LessBundle : Bundle
{
public LessBundle(string virtualPath) : base(virtualPath, new IBundleTransform[] {new LessTransform(), new CssMinify()})
{
}
public LessBundle(string virtualPath, string cdnPath)
: base(virtualPath, cdnPath, new IBundleTransform[] { new LessTransform(), new CssMinify() })
{
}
}
}
用法类似于StyleBundle类,指定一个LESS文件,而不是一个CSS文件。
以下内容添加到您的BundleConfig.RegisterBundles(BundleCollection)方法:
bundles.Add(new LessBundle("~/Content/less").Include(
"~/Content/MyStyles.less"));
更新
与优化关掉,但我遇到了一些小问题(与CSS资源路径)时,优化被打开,此方法效果很好。 一个小时研究这个问题后,我发现,我已经重新发明轮子...
如果你想LessBundle功能我上面的描述,请System.Web.Optimization.Less 。
该NuGet包可以找到这里 。
Answer 3:
接受的答案并不最近更改ASP.NET工作,所以不再正确。
我已经固定在接受的答案来源:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Hosting;
using System.Web.Optimization;
using dotless.Core;
using dotless.Core.Abstractions;
using dotless.Core.Importers;
using dotless.Core.Input;
using dotless.Core.Loggers;
using dotless.Core.Parser;
namespace Web.App_Start.Bundles
{
public class LessTransform : IBundleTransform
{
public void Process(BundleContext context, BundleResponse bundle)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (bundle == null)
{
throw new ArgumentNullException("bundle");
}
context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies();
var lessParser = new Parser();
ILessEngine lessEngine = CreateLessEngine(lessParser);
var content = new StringBuilder(bundle.Content.Length);
var bundleFiles = new List<BundleFile>();
foreach (var bundleFile in bundle.Files)
{
bundleFiles.Add(bundleFile);
var name = context.HttpContext.Server.MapPath(bundleFile.VirtualFile.VirtualPath);
SetCurrentFilePath(lessParser, name);
using (var stream = bundleFile.VirtualFile.Open())
using (var reader = new StreamReader(stream))
{
string source = reader.ReadToEnd();
content.Append(lessEngine.TransformToCss(source, name));
content.AppendLine();
}
bundleFiles.AddRange(GetFileDependencies(lessParser));
}
if (BundleTable.EnableOptimizations)
{
// include imports in bundle files to register cache dependencies
bundle.Files = bundleFiles.Distinct();
}
bundle.ContentType = "text/css";
bundle.Content = content.ToString();
}
/// <summary>
/// Creates an instance of LESS engine.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
private ILessEngine CreateLessEngine(Parser lessParser)
{
var logger = new AspNetTraceLogger(LogLevel.Debug, new Http());
return new LessEngine(lessParser, logger, true, false);
}
/// <summary>
/// Gets the file dependencies (@imports) of the LESS file being parsed.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
/// <returns>An array of file references to the dependent file references.</returns>
private IEnumerable<BundleFile> GetFileDependencies(Parser lessParser)
{
IPathResolver pathResolver = GetPathResolver(lessParser);
foreach (var importPath in lessParser.Importer.Imports)
{
yield return
new BundleFile(pathResolver.GetFullPath(importPath),
HostingEnvironment.VirtualPathProvider.GetFile(importPath));
}
lessParser.Importer.Imports.Clear();
}
/// <summary>
/// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
private IPathResolver GetPathResolver(Parser lessParser)
{
var importer = lessParser.Importer as Importer;
var fileReader = importer.FileReader as FileReader;
return fileReader.PathResolver;
}
/// <summary>
/// Informs the LESS parser about the path to the currently processed file.
/// This is done by using a custom <see cref="IPathResolver"/> implementation.
/// </summary>
/// <param name="lessParser">The LESS parser.</param>
/// <param name="currentFilePath">The path to the currently processed file.</param>
private void SetCurrentFilePath(Parser lessParser, string currentFilePath)
{
var importer = lessParser.Importer as Importer;
if (importer == null)
throw new InvalidOperationException("Unexpected dotless importer type.");
var fileReader = importer.FileReader as FileReader;
if (fileReader == null || !(fileReader.PathResolver is ImportedFilePathResolver))
{
fileReader = new FileReader(new ImportedFilePathResolver(currentFilePath));
importer.FileReader = fileReader;
}
}
}
}
请注意一个已知的问题与此代码的是LESS @imports必须使用他们的完整路径,即你必须使用@import "~/Areas/Admin/Css/global.less";
代替@import "global.less";
。
Answer 4:
像这样的作品-我改变了Process
方法遍历文件集:
public void Process(BundleContext context, BundleResponse response)
{
var builder = new StringBuilder();
foreach (var fileInfo in response.Files)
{
using (var reader = fileInfo.OpenText())
{
builder.Append(dotless.Core.Less.Parse(reader.ReadToEnd()));
}
}
response.Content = builder.ToString();
response.ContentType = "text/css";
}
这打破了,如果有任何@import
在你不太文件的语句不过,在这种情况下,你必须做更多的工作,像这样: https://gist.github.com/chrisortman/2002958
Answer 5:
目前已经有一些伟大的答案,这里是一个非常简单的解决方案试图增加这方面的MVC束时,我发现我自己less
文件。
创建后less
的文件(例如, test.less
),右键点击它,并在网页编译器( 把它在这里 )选项中,选择Compile File
。
这会产生所产生的css
从您的文件less
之一,也是其缩小的版本。 ( test.css
和test.min.css
)。
在你的包,只是引用生成css
文件
style = new StyleBundle("~/bundles/myLess-styles")
.Include("~/Content/css/test.css", new CssRewriteUrlTransform());
bundles.Add(style);
和你的观点,引用包:
@Styles.Render("~/bundles/myLess-styles")
它应该只是正常工作。
文章来源: How to use ASP.Net MVC 4 to Bundle LESS files in Release mode?