Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dotless engine parser returns empty string

ASP.Net MVC4 + Bootstrap (LESS) + dotLess.

Goal is to transform the Bootstrap .less files into a single bundle of .css, and I'm running into showstopper issues.

Bundle.config

var bootstrapStyles = new Bundle("~/bundle/style/bootstrap").Include("~/Content/less/*.less");
bootstrapStyles.Transforms.Add(new LessTransform());
bootstrapStyles.Transforms.Add(new CssMinify());
bundles.Add(bootstrapStyles);

Only bootstrap's less files, which should not have any red-flag syntax problems.

The next step was to build that transformer class LessTransform to produce the css.

The transformer class implements the Process() and the problematic code exists inside... here's both scenarios and their problems:

Scenario 1: Static Less.Parse()

var parsedLess = Less.Parse(bundle.Content);
bundle.Content = parsedLess;

// Throws a FileNotFoundException
// "You are importing a file ending in .less that cannot be found."
// reset.less and it definitely exists in that folder. 

Scenario 2: LessEngine.TransformToCss()

var content = new StringBuilder();
var engine = new LessEngine();

foreach (var file in bundle.Files)
{
    // text is extracted correctly.
    var text = File.ReadAllText(file.FullName);
    // transform function returns an empty string, no errors
    var css = engine.TransformToCss(text, file.FullName);
    content.AppendLine(css);
}
bundle.Content = content.ToString();

Question

Anyone have an insight on either of these errors? Know any solutions? Neither make sense to me. Thanks.

like image 357
one.beat.consumer Avatar asked Sep 28 '12 19:09

one.beat.consumer


2 Answers

Wow! That's a lot of hoop jumping to find the source of the problem.

A good strategy for such problems is to peel away the layers to the simplest case. You're not seeing any error messages because something in the bundling process is eating up dotless's logging messages, which should be dealt with separately. This assumes you have dotless error logging turned on.

Instead, of using:

@Styles.Render("~/bundle/style/bootstrap")

use

<link rel="stylesheet/less" href="~/Content/style/bootstrap.less" type="text/css" />

When you try to view the less file in the browser, you should get the following message:

directive block with unrecognised format on line 253 in file '/Content/Themes/bootstrap/mixins.less':

[252]: // Multiple shadow solution from http://toekneestuck.com/blog/2012/05/15/less-css-arguments-variable/ [253]: @props: ~"@{arguments}".replace(/[\[\]]|\,\sX/g, ''); --^ [254]: -webkit-box-shadow: @props;

The source of this problem is attributed to a hack in bootstrap that doesn't play well with dotless. To fix this problem, replace the following lines in mixins.less:

// Drop shadows
.box-shadow(@shadowA, @shadowB:X, ...){
  // Multiple shadow solution from http://toekneestuck.com/blog/2012/05/15/less-css-arguments-variable/
  @props: ~`"@{arguments}".replace(/[\[\]]|\,\sX/g, '')`;
  -webkit-box-shadow: @props;
     -moz-box-shadow: @props;
          box-shadow: @props;
}

with the following lines:

// Drop shadows
.box-shadow(@shadow){
  -webkit-box-shadow: @shadow;
     -moz-box-shadow: @shadow;
          box-shadow: @shadow;
}
.box-shadow(@shadow1, @shadow2) {
  -webkit-box-shadow: @shadow1, @shadow2;
     -moz-box-shadow: @shadow1, @shadow2;
          box-shadow: @shadow1, @shadow2;
}
.box-shadow(@shadow1, @shadow2, @shadow3) {
  -webkit-box-shadow: @shadow1, @shadow2, @shadow3;
     -moz-box-shadow: @shadow1, @shadow2, @shadow3;
          box-shadow: @shadow1, @shadow2, @shadow3;
}

Hope this works for you.

like image 190
ATL_DEV Avatar answered Oct 24 '22 11:10

ATL_DEV


Scenario 1 (Solved)

It turns out, it was not actually failing on 'reset.less' but on 'bootstrap.less' who's first line is an import statement to 'reset.less'. Implementing a path resolver in the loop fixed that issue.

// let them throw exceptions on casting because they should never be null.
var importer = (Importer)lessParser.Importer;
var filereader = (FileReader)importer.FileReader;
// "As" casting here ensures if the path resolver is another type that we cannot cast 
// (ex. RelativePathResolver) that we get a null rather than an exception.
var pathresolver = filereader.PathResolver as ImportedFilePathResolver;
if (pathresolver != null)
    pathresolver.CurrentFilePath = currentFilePath;
else
    filereader.PathResolver = new ImportedFilePathResolver(currentFilePath);

Scenario 2 (Still Broken)

See Joel's answer above. It is correct. One thing to note, this Tony Stark hack will be removed from Bootstrap 2.1.2, just around the corner: https://github.com/twitter/bootstrap/issues/5079

like image 36
one.beat.consumer Avatar answered Oct 24 '22 10:10

one.beat.consumer