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());
CssMinify
在System.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缩小器,而不是将其作为参数传入。
要使MicrosoftAjaxCssMinifier成为默认的CSS-minifier和MicrosoftAjaxJsMinifier默认的JS-minifier,您需要对Web.config文件进行更改。 在\ configuration \ bundleTransformer \ core \ css元素的defaultMinifier属性中,必须设置值等于MicrosoftAjaxCssMinifier ,并且在\ configuration \ bundleTransformer \ core \ js元素的相同属性 – MicrosoftAjaxJsMinifier中。
我已经通过相同的问题,看到相同的错误信息。 在互联网上寻找解决scheme把我带到这里。 我的问题如下:
在一个较less的文件中,我曾经有过一个不正确的风格,给我一个警告。 无法parsing的文件越less。 我通过删除不正确的行来摆脱错误信息。
我希望这可以帮助别人。