4

I all I am using DotLess with a LessTransformer.cs I found online, In my MVC 4 project.

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Optimization;
using MyNamespace.Infrastructure.Bundler;
using dotless.Core.configuration;

namespace MyNameSpace.Infrastructure.Transformers.Less
{
    public class LessTransform : IBundleTransform
    {
        private readonly DotlessConfiguration _configuration;

        public LessTransform(DotlessConfiguration configuration)
        {
            _configuration = configuration;
        }

        public LessTransform()
            : this(DotlessConfiguration.GetDefaultWeb())
        { }

        public void Process(BundleContext context, BundleResponse response)
        {
            var builder = new StringBuilder();

            _configuration.MinifyOutput         = false;
            _configuration.ImportAllFilesAsLess = true;
            _configuration.CacheEnabled         = false;
            _configuration.LessSource           = typeof(VirtualFileReader);

            foreach (var file in response.Files)
            {
                if (!File.Exists(file.FullName))
                {
                    continue;
                }

                var content = ResolveImports(file);

                builder.AppendLine((_configuration.Web) ?
                                    dotless.Core.LessWeb.Parse(content, _configuration)
                                    : dotless.Core.Less.Parse(content, _configuration));
            }

            response.ContentType = "text/css";
            response.Content = builder.ToString();
        }

        private static readonly Regex SLessImportRegex =
            new Regex("@import [\"|'](.+)[\"|'];", RegexOptions.Compiled);

        private static string ResolveImports(FileInfo file)
        {
            var content = File.ReadAllText(file.FullName, Encoding.UTF8);

            return SLessImportRegex.Replace(
                content,
                match =>
                {
                    var import = match.Groups[1].Value;

                    // Is absolute path?
                    Uri uri;
                    if (Uri.TryCreate(import, UriKind.Absolute, out uri))
                    {
                        return match.Value;
                    }

                    var path = Path.Combine(file.Directory.FullName, import);

                    if (!File.Exists(path))
                    {
                        throw new ApplicationException(string.Concat("Unable to resolve import ", import));
                    }
                    return match.Value.Replace(import, path);
                });
        }
    }
}

I have since added to this

_configuration.MinifyOutput         = false;
_configuration.ImportAllFilesAsLess = true;
_configuration.CacheEnabled         = false;
_configuration.LessSource           = typeof(VirtualFileReader);



using System.IO;
using System.Web.Hosting;
using dotless.Core.Input;

namespace MyNamespace.Infrastructure.Bundler
{
    internal sealed class VirtualFileReader : IFileReader
    {
        public byte[] GetBinaryFileContents(string fileName)
        {
            fileName = GetFullPath(fileName);
            return File.ReadAllBytes(fileName);
        }

        public string GetFileContents(string fileName)
        {
            fileName = GetFullPath(fileName);
            return File.ReadAllText(fileName);
        }

        public bool DoesFileExist(string fileName)
        {
            fileName = GetFullPath(fileName);
            return File.Exists(fileName);
        }

        private static string GetFullPath(string path)
        {
            return HostingEnvironment.MapPath("\\Content\\css\\" + path);
        }
    }
}

I have a Less file

@import url('LESS\Site.less');
@import url('LESS\Site.Main.less');

body {
    #featured-posts {
        clear:both;
    }
}

@media all and (max-width:320px) {
   @import url('LESS\Site.Mobile.less');
}

(Which I have tried various paths for the imports and /w and /wo function notation url()

Which is all pulled in my BundleConfig

    Bundle siteStyles = new      StyleBundle("~/bundles/css").Include("~/Content/css/Main.less");
    siteStyles.Transforms.Add(new LessTransform());
    siteStyles.Transforms.Add(new CssMinify());
    bundles.Add(siteStyles);

before I added the VirtualFileReader I was getting the error:-

C:/SourceControl/Git/MyNameSpace/MyNameSpace/Content/css/LESS/Site.less' is a physical path, but a virtual path was expected.

since I adding it I get simply the value is null on dotless.Core.LessWeb.Parse(content, _configuration)

it always blow up on this line, granted I've been a bit gun-ho implementing this less stuff and dotless because I haven't used either before, but I can't seem to find any good solid documentations/tutorials on it. So if you could help me out with my error that would be great and point me in the direction of some good tutorials on the subject I would be very grateful.

[EDIT] adding details on less files and file structure.

My File structure is 

Content/css/Main.less
Content/css/LESS/Site.less
Content/css/LESS/Mobile.less

etc... TIA.

p.s. don't worry about the MyNamespace/MyNamespace stuff I've just shortened it all for clarity.

JTGrime
  • 53
  • 6
  • Try changing `StyleBundle("~/bundles/css")` to `StyleBundle("~/Content/css/css")` – MikeSmithDev Apr 08 '13 at 15:25
  • Also it seems like it'd be more efficient to bundle all your styles instead of using `@imports`. – MikeSmithDev Apr 08 '13 at 15:37
  • It might be more efficient, but the LESS spec calls for `@imports`. And in theory BundleTransform does the "bundling" for us. – mxmissile Apr 08 '13 at 15:42
  • Nope, tried it with the VirtualFileReader.cs and without in the LessTransformer.cs. I get the following error{"You are importing a file ending in .less that cannot be found.":"LESS\\Site.less"} – JTGrime Apr 08 '13 at 15:42
  • Minor point but shouldn't you be using forward slashes in your import statements? – Dave Hogan Apr 08 '13 at 15:43
  • @JTGrime I've been down this road twice, gave up. Ended up not using the built in Bundling and just used the dotLess stuff as normal. I'm interested to see how this comes out. – mxmissile Apr 08 '13 at 15:44
  • @DaveHogan I've tried both, when stepping through it last night I found it was using '\' and not '/' so I matched it. I've pretty much tried every combination I can think of in terms of the less code. – JTGrime Apr 08 '13 at 15:44
  • @mxmissile yeah I really want to see this through, I have a nice little idea for a pattern in my head for dynamically building client bundles. – JTGrime Apr 08 '13 at 15:45

1 Answers1

0

I don't understand why you are using the custom transformer.

LESS specification says that if you use the following syntax the file will be bundled automatically:

@import "LESS/Site";

It works perfectly for me, I don't need any custom transformers, only the standard dotless package. To enable minification you need this setting in the web.config:

<dotless minifyCss="true" cache="true" web="true" />

I have around 30 imports of components and sub components and the output is a single minified file.

I suggest you to not use the style bundle but to point directly to your less file:

<link href="~/Content/css/main.less" rel="stylesheet" />

The dotless http handler will kick in, convert the less to css and cache it for subsequent requests

Marco Bettiolo
  • 5,071
  • 6
  • 30
  • 35
  • ahh I actually resolved this a fair few weeks ago, I just hadn't had time to reply to it since starting a new job. Thanks for the response though. – JTGrime May 24 '13 at 13:47
  • @JTGrime Was mine the correct answer? Have you resolved your issue in a different way? – Marco Bettiolo May 25 '13 at 12:51
  • @MarcoBettiolo are there adverse affects for browser caching using this approach? Meaning, if you don't use bundling with cache keys updates will be problematic? – ctc Oct 17 '13 at 16:56
  • @ctc I seen a nice improvement in the browser caching, the bundling generates a hash value for the specific generated bundle, as long as the bundle does not change, the key stays the same. If you do not use the cache keys, then your browser my cache the wrong style. I suggest using proper cache headers to mitigate this issue. – Marco Bettiolo Oct 24 '13 at 10:32