MVC4减去捆绑@import目录

我试图使用MVC4捆绑将我的一些less文件,但它看起来像我使用的导入path是closures的。 我的目录结构是:

static/ less/ mixins.less admin/ user.less 

在user.less,我试图导入mixins.less使用这个:

 @import "../mixins.less"; 

之前用这种方法为我工作时,无聊的啁啾,但现在我注意到ELMAH正在生我的气,说:

 System.IO.FileNotFoundException: You are importing a file ending in .less that cannot be found. File name: '../mixins.less' 

我应该使用MVC4不同的@import吗?

一些额外的信息

下面是我用来尝试这个的less class和global.asax.cs代码:

LessMinify.cs

 ... public class LessMinify : CssMinify { public LessMinify() {} public override void Process(BundleContext context, BundleResponse response) { response.Content = Less.Parse(response.Content); base.Process(context, response); } } ... 

Global.asax.cs

 ... DynamicFolderBundle lessFB = new DynamicFolderBundle("less", new LessMinify(), "*.less"); BundleTable.Bundles.Add(lessFB); Bundle AdminLess = new Bundle("~/AdminLessBundle", new LessMinify()); ... AdminLess.AddFile("~/static/less/admin/user.less"); BundleTable.Bundles.Add(AdminLess); ... 

我写了一篇关于在MVC4 Web Optimization中使用LESS CSS的快速博客文章。

它基本上归结为使用BundleTransformer.Less Nuget包和更改您的BundleConfig.cs。

testing自举。

编辑:应该提到我这样说的原因,我也遇到了@import目录结构问题,这个库正确处理它。

在GitHub Gist上发布了与@import和dotLess很好地结合的代码: https ://gist.github.com/2002958

我用Twitter Bootstraptesting过,效果很好。

ImportedFilePathResolver.cs

 public class ImportedFilePathResolver : IPathResolver { private string currentFileDirectory; private string currentFilePath; /// <summary> /// Initializes a new instance of the <see cref="ImportedFilePathResolver"/> class. /// </summary> /// <param name="currentFilePath">The path to the currently processed file.</param> public ImportedFilePathResolver(string 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) { filePath = filePath.Replace('\\', '/').Trim(); if(filePath.StartsWith("~")) { filePath = VirtualPathUtility.ToAbsolute(filePath); } if(filePath.StartsWith("/")) { filePath = HostingEnvironment.MapPath(filePath); } else if(!Path.IsPathRooted(filePath)) { filePath = Path.Combine(currentFileDirectory, filePath); } return filePath; } } 

LessMinify.cs

 public class LessMinify : IBundleTransform { /// <summary> /// Processes the specified bundle of LESS files. /// </summary> /// <param name="bundle">The LESS bundle.</param> public void Process(BundleContext context, BundleResponse bundle) { 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); foreach(FileInfo file in bundle.Files) { SetCurrentFilePath(lessParser, file.FullName); string source = File.ReadAllText(file.FullName); content.Append(lessEngine.TransformToCss(source, file.FullName)); content.AppendLine(); AddFileDependencies(lessParser); } bundle.Content = content.ToString(); bundle.ContentType = "text/css"; //base.Process(context, bundle); } /// <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, false); } /// <summary> /// Adds imported files to the collection of files on which the current response is dependent. /// </summary> /// <param name="lessParser">The LESS parser.</param> private void AddFileDependencies(Parser lessParser) { IPathResolver pathResolver = GetPathResolver(lessParser); foreach(string importedFilePath in lessParser.Importer.Imports) { string fullPath = pathResolver.GetFullPath(importedFilePath); HttpContext.Current.Response.AddFileDependency(fullPath); } lessParser.Importer.Imports.Clear(); } /// <summary> /// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser. /// </summary> /// <param name="lessParser">The LESS prser.</param> private IPathResolver GetPathResolver(Parser lessParser) { var importer = lessParser.Importer as Importer; if(importer != null) { var fileReader = importer.FileReader as FileReader; if(fileReader != null) { return fileReader.PathResolver; } } return null; } /// <summary> /// Informs the LESS parser about the path to the currently processed file. /// This is done by using 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) { var fileReader = importer.FileReader as FileReader; if(fileReader == null) { importer.FileReader = fileReader = new FileReader(); } var pathResolver = fileReader.PathResolver as ImportedFilePathResolver; if(pathResolver != null) { pathResolver.CurrentFilePath = currentFilePath; } else { fileReader.PathResolver = new ImportedFilePathResolver(currentFilePath); } } else { throw new InvalidOperationException("Unexpected importer type on dotless parser"); } } } 

本·库尔的答案附录:

我知道这个“应该是对本·库尔的post的评论”,但它增加了一些额外的,不可能添加评论。 所以如果你一定要投我一票。 或者closures我。

本的博客文章是这样做的,除了没有指定缩小。

所以按照Ben的build议安装BundleTransformer.Less包,然后,如果你想缩小你的css,请执行以下操作(在〜/ App_Start / BundleConfig.cs中):

 var cssTransformer = new CssTransformer(); var jsTransformer = new JsTransformer(); var nullOrderer = new NullOrderer(); var css = new Bundle("~/bundles/css") .Include("~/Content/site.less"); css.Transforms.Add(cssTransformer); css.Transforms.Add(new CssMinify()); css.Orderer = nullOrderer; bundles.Add(css); 

增加的行是:

 css.Transforms.Add(new CssMinify()); 

CssMinifySystem.Web.Optimizations

绕过@import问题,我感到非常放心,没有find我没有意识到谁投票给我。

相反,如果您觉得投票select这个答案的冲动,请将您的投票给本。

那么在那里。

一个解决scheme,我发现真正有用的是在LessMinify.Process()运行Less.Parse之前设置目录。 我是这样做的:

 public class LessTransform : IBundleTransform { private string _path; public LessTransform(string path) { _path = path; } public void Process(BundleContext context, BundleResponse response) { Directory.SetCurrentDirectory(_path); response.Content = Less.Parse(response.Content); response.ContentType = "text/css"; } } 

然后在创build较less转换对象时传递path,如下所示:

 lessBundle.Transforms.Add( new LessTransform(HttpRuntime.AppDomainAppPath + "/Content/Less") ); 

希望这可以帮助。

问题是DynamicFolderBundle读取文件的所有内容,并将组合内容传递给LessMinify。

因为任何@imports都没有引用文件来自的位置。

为了解决这个问题,我必须把所有的“less”文件放到一个位置。

那么你必须了解文件的顺序变得重要。 因此,我开始用一个数字(例如:“0 CONSTANTS.less”,“1 MIXIN.less”)来重命名文件,这意味着它们在进入LessMinify之前被加载到组合输出的顶部。

如果你debugging你的LessMinify并查看response.Content,你会看到组合输出较less!

希望这可以帮助

下面是代码的最简单版本来处理我可以想到的:

 public class LessTransform : IBundleTransform { public void Process(BundleContext context, BundleResponse bundle) { var pathResolver = new ImportedFilePathResolver(context.HttpContext.Server); var lessParser = new Parser(); var lessEngine = new LessEngine(lessParser); (lessParser.Importer as Importer).FileReader = new FileReader(pathResolver); var content = new StringBuilder(bundle.Content.Length); foreach (var bundleFile in bundle.Files) { pathResolver.SetCurrentDirectory(bundleFile.IncludedVirtualPath); content.Append(lessEngine.TransformToCss((new StreamReader(bundleFile.VirtualFile.Open())).ReadToEnd(), bundleFile.IncludedVirtualPath)); content.AppendLine(); } bundle.ContentType = "text/css"; bundle.Content = content.ToString(); } } public class ImportedFilePathResolver : IPathResolver { private HttpServerUtilityBase server { get; set; } private string currentDirectory { get; set; } public ImportedFilePathResolver(HttpServerUtilityBase server) { this.server = server; } public void SetCurrentDirectory(string fileLocation) { currentDirectory = Path.GetDirectoryName(fileLocation); } public string GetFullPath(string filePath) { var baseDirectory = server.MapPath(currentDirectory); return Path.GetFullPath(Path.Combine(baseDirectory, filePath)); } } 

以下是我所做的:

添加了Twitter Bootstrap Nuget模块。

添加到我的_Layout.cshtml文件中:

 <link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/twitterbootstrap/less")" rel="stylesheet" type="text/css" /> 

请注意,我将我的“less”文件夹重命名为twitterbootstrap,以certificate我可以

将所有较less的文件移动到名为“imports”的子文件夹中, 除了 bootstrap.less和(用于响应式devise) responsive.less

 ~/Content/twitterbootstrap/imports 

在web.config中添加了一个configuration:

 <add key="TwitterBootstrapLessImportsFolder" value="imports" /> 

创build了两个类(上面的类稍作修改):

 using System.Configuration; using System.IO; using System.Web.Optimization; using dotless.Core; using dotless.Core.configuration; using dotless.Core.Input; namespace TwitterBootstrapLessMinify { public class TwitterBootstrapLessMinify : CssMinify { public static string BundlePath { get; private set; } public override void Process(BundleContext context, BundleResponse response) { setBasePath(context); var config = new DotlessConfiguration(dotless.Core.configuration.DotlessConfiguration.GetDefault()); config.LessSource = typeof(TwitterBootstrapLessMinifyBundleFileReader); response.Content = Less.Parse(response.Content, config); base.Process(context, response); } private void setBasePath(BundleContext context) { var importsFolder = ConfigurationManager.AppSettings["TwitterBootstrapLessImportsFolder"] ?? "imports"; var path = context.BundleVirtualPath; path = path.Remove(path.LastIndexOf("/") + 1); BundlePath = context.HttpContext.Server.MapPath(path + importsFolder + "/"); } } public class TwitterBootstrapLessMinifyBundleFileReader : IFileReader { public IPathResolver PathResolver { get; set; } private string basePath; public TwitterBootstrapLessMinifyBundleFileReader() : this(new RelativePathResolver()) { } public TwitterBootstrapLessMinifyBundleFileReader(IPathResolver pathResolver) { PathResolver = pathResolver; basePath = TwitterBootstrapLessMinify.BundlePath; } public bool DoesFileExist(string fileName) { fileName = PathResolver.GetFullPath(basePath + fileName); return File.Exists(fileName); } public string GetFileContents(string fileName) { fileName = PathResolver.GetFullPath(basePath + fileName); return File.ReadAllText(fileName); } } } 

我的IFileReader实现查看TwitterBootstrapLessMinify类的静态成员BundlePath。 这使我们能够为导入注入一个基本path。 我本来希望采取不同的方法(通过提供我的class级的实例,但我不能)。

最后,我将下面几行添加到Global.asax中:

 BundleTable.Bundles.EnableDefaultBundles(); var lessFB = new DynamicFolderBundle("less", new TwitterBootstrapLessMinify(), "*.less", false); BundleTable.Bundles.Add(lessFB); 

这有效地解决了import不知道从哪里import的问题。

截至2013年2月:Michael Baird的出色解决scheme被Ben Cull的post中提到的“BundleTransformer.Less Nuget Package”所取代。 类似的答案在: http : //blog.cdeutsch.com/2012/08/using-less-and-twitter-bootstrap-in.html

Cdeutsch的博客和awrigley的post中增加了缩小是好的,但显然现在不是正确的方法。

其他人使用相同的解决scheme从BundleTransformer作者得到一些答案: http ://geekswithblogs.net/ToStringTheory/archive/2012/11/30/who-could-ask-for-more-with-less-css-part- 2.aspx 。 请参阅底部的评论。

总之使用BundleTransformer.MicrosoftAjax代替内置的minifiers。 例如css.Transforms.Add(new CssMinify()); 换成css.Transforms.Add(新的BundleTransformer.MicrosoftAjax());

在下面的RockResolve之后,要使用MicrosoftAjax缩小器,请将其作为web.config中的默认CSS缩小器,而不是将其作为参数传入。

https://bundletransformer.codeplex.com/wikipage/?title=Bundle%20Transformer%201.7.0%20Beta%201#BundleTransformerMicrosoftAjax_Chapter

要使MicrosoftAjaxCssMinifier成为默认的CSS-minifier和MicrosoftAjaxJsMinifier默认的JS-minifier,您需要对Web.config文件进行更改。 在\ configuration \ bundleTransformer \ core \ css元素的defaultMinifier属性中,必须设置值等于MicrosoftAjaxCssMinifier ,并且在\ configuration \ bundleTransformer \ core \ js元素的相同属性 – MicrosoftAjaxJsMinifier中。

我已经通过相同的问题,看到相同的错误信息。 在互联网上寻找解决scheme把我带到这里。 我的问题如下:

在一个较less的文件中,我曾经有过一个不正确的风格,给我一个警告。 无法parsing的文件越less。 我通过删除不正确的行来摆脱错误信息。

我希望这可以帮助别人。