MVC4 Less Bundle @import Directory

I am trying to use MVC4 binding to group some of my smaller files, but it looks like the import path I'm using is disabled. My directory structure:

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

In user.less, I am trying to import mixins.less using this:

 @import "../mixins.less"; 

This was used for me before when I used chirpy with countless numbers, but now I noticed that ELMAH is mad at me by saying this:

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

Should I use another @import with MVC4?

Additional Information

Here's the less class and global.asax.cs code that I use to do this:

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); ... 
+51
import less asp.net-mvc-4 bundle asp.net-optimization
Mar 6 2018-12-12T00:
source share
11 answers

I wrote a short blog post on Using LESS CSS with MVC4 Web Optimization .

It basically boils down to using the BundleTransformer.Less Nuget package and modifying your BundleConfig.cs.

Tested with bootstrap.

EDIT: The reason why I say this should be mentioned, I also ran into the @import directory structure problem, and this library handles it correctly.

+41
Oct 02
source share
— -

GitHub Gist has code that works well with @import and dotLess: https://gist.github.com/2002958

I tested it with Twitter Bootstrap and it works well.

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"); } } } 
+26
Aug 06 2018-12-12T00:
source share

Addendum to Ben Kull's answer:

I know that this “should be a comment on Ben Kull’s post,” but it adds a little extra, which would be impossible to add to the comment. So vote if you want. Or shut me down.

Ben's blog blog does all this, except that he does not indicate minimization.

So, install the BundleTransformer.Less package, as Ben suggests, and then, if you want to minimize your css, follow these steps (in ~ / 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); 

Added line:

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

Where CssMinify is located in System.Web.Optimizations

I am so pleased to get rid of the @import problem, and the resulting file with the .less extension did not find that I do not care who votes me.

If, on the contrary, you feel like voting for this answer, please give your vote to Ben.

So there.

+21
Oct 31 '12 at 17:38
source share

The work that I found was very useful was to set up a directory before running Less.Parse inside LessMinify.Process (). Here is how I did it:

 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"; } } 

Then going through the path when creating an object with less transformation as follows:

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

Hope this helps.

+17
Oct 02 '13 at
source share

The problem is that DynamicFolderBundle reads all the contents of the files and passes the combined contents to LessMinify.

Thus, any @imports do not have a link to the location from which the file was received.

To solve this problem, I had to put all the "less" files in one place.

Then you should understand that the order of the files becomes important. So I started to rename the file with the number (for example: "0 CONSTANTS.less", "1 MIXIN.less", which means that they are loaded at the top of the combined output before they enter LessMinify.

if you are debugging your LessMinify and looking at the answer. Content you will see combined less output.

Hope this helps

+4
Mar 15 2018-12-12T00:
source share

Here's the simplest version of the code to handle this I could come up with:

 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)); } } 
+3
Jun. 19 '14 at 15:03
source share

Here is what I did:

Added Twitter Bootstrap Nuget module.

Added this to my _Layout.cshtml file:

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

Please note that I renamed my “smaller” folder to twitterbootstrap to demonstrate that I could

Moved all the less files to a subfolder called "import" except bootstrap.less and (for responsive design) responsive .less.

 ~/Content/twitterbootstrap/imports 

Added configuration in web.config file:

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

Two classes have been created (a small modification of the class above):

 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); } } } 

My implementation of IFileReader examines the static member of the BundlePath of the TwitterBootstrapLessMinify class. This allows us to enter the base path for the import. I would like to use a different approach (by providing an instance of my class, but I could not).

Finally, I added the following lines to Global.asax:

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

This effectively solves the import problem without knowing where to import.

+2
May 25 '12 at 4:48
source share

As of February 2013: Michael Baird’s idea was excellently resolved due to the answer “BundleTransformer.Less Nuget Package” mentioned in Ben Kull’s post. Related answers: http://blog.cdeutsch.com/2012/08/using-less-and-twitter-bootstrap-in.html

Cdeutsch blog and awrigley post adding minification is good, but apparently now the wrong approach.

Someone else with the same solution received answers from the author of BundleTransformer: http://geekswithblogs.net/ToStringTheory/archive/2012/11/30/who-could-ask-for-more-with-less-css-part- 2.aspx . See comments below.

In conclusion, use BundleTransformer.MicrosoftAjax instead of the built-in built-in minifiers. e.g. css.Transforms.Add (new CssMinify ()); replaced by css.Transforms.Add (new BundleTransformer.MicrosoftAjax ());

+1
Feb 08 '13 at 0:20
source share

Further, using the RockResolve below to use the MicrosoftAjax minifier, refer to it as the default CSS minifier in the web.config by default, and not pass it as an argument.

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

To have MicrosoftAjaxCssMinifier default CSS minifier and MicrosoftAjaxJsMinifier default JS minifier, you need to make changes to the Web.config file. The defaultMinifier attribute of the \ configuration \ bundleTransformer \ core \ css element must be set to MicrosoftAjaxCssMinifier , and the MicrosoftAjaxJsMinifier is set to the same \ configuration \ bundleTransformer \ core \ js element attribute.

+1
Apr 16 '13 at 20:05
source share

Check out my library https://www.nuget.org/packages/LessMVCFour Hope this helps.

0
Apr 18 '13 at 8:26
source share

I ran into the same problem seeing the same error message. Finding a solution on the Internet brought me here. My problem was this:

In a smaller file, at some point I had the wrong style that gave me a warning. The smaller the files cannot be parsed. I got rid of the error message by deleting the wrong line.

I hope this helps someone.

-one
Dec 09 '13 at 13:26
source share



All Articles