Like mentioned by AlexCuse, there was no way for me to do what I mentioned above using only SquishIt. However, as mentioned in https://github.com/jetheredge/SquishIt/issues/170, there is an overload to AddString() that lets you add dynamic less content.
For example,
.AddString("LessString",".less") // .less being the extension
This works perfectly fine as long as the LessString does not contain any imports (@import). So, I downloaded the source from https://github.com/jetheredge/SquishIt and started diving into the code. Going through the code I found that the content loaded through AddString() has the CurrentDirectory set to the path of my IIS ("c:\windows\system32\inetsrv"). As a result of which, the imports were throwing
FileNotFoundException (You are importing a file ending in .less that
cannot be found.)
So, I needed a way to set the current directory (reference location from where my imports will be searched)
Here is what I did:
STEP1: Extended Asset to have a property called CurrentDirectory
internal string CurrentDirectory { get; set; }
STEP2: Added a third optional parameter to the AddString() overload
public T AddString(string content, string extension, string currentDirectory = null)
{
return AddString(content, extension, true, currentDirectory);
}
STEP3: Updated the AddString() to add the current directory to the Asset
T AddString(string content, string extension, bool minify, string currentDirectory = null)
{
if (bundleState.Assets.All(ac => ac.Content != content))
bundleState.Assets.Add(new Asset { Content = content, Extension = extension, Minify = minify, CurrentDirectory = currentDirectory });
return (T)this;
}
STEP4: Modify the PreprocessArbitary (For Release) on BundleBase to set the current directory
protected string PreprocessArbitrary(Asset asset)
{
if (!asset.IsArbitrary) throw new InvalidOperationException("PreprocessArbitrary can only be called on Arbitrary assets.");
var filename = "dummy." + (asset.Extension ?? defaultExtension);
var preprocessors = FindPreprocessors(filename);
return asset.CurrentDirectory != null ?
directoryWrapper.ExecuteInDirectory(asset.CurrentDirectory, () => MinifyIfNeeded(PreprocessContent(filename, preprocessors, asset.Content), asset.Minify)) :
MinifyIfNeeded(PreprocessContent(filename, preprocessors, asset.Content), asset.Minify);
}
For Debug, modify the RenderDebug to set the current directory
if (asset.IsArbitrary)
{
var filename = "dummy" + asset.Extension;
var preprocessors = FindPreprocessors(filename);
var processedContent = asset.CurrentDirectory != null ?
directoryWrapper.ExecuteInDirectory(asset.CurrentDirectory, () => PreprocessContent(filename, preprocessors, asset.Content)) :
PreprocessContent(filename, preprocessors, asset.Content);
sb.AppendLine(string.Format(tagFormat, processedContent));
}
Here is my how I add dynamic or static less files now:
.AddString("@import 'content/bootstrap/variables.less';", ".less", AppDomain.CurrentDomain.BaseDirectory)
For my above requirement, I read the variables.less into a string builder, then add my variable-override.less and finally add the bootstrap-without-variables.less to the string builder.
It has worked for me so far. I tested following scenarios:
normal less files with imports, e.g. .Add("~/content/styles.less")
inline less without imports, e.g. .AddString(LessString, ".less")
dynamic less files with imports, e.g. .AddString("@import content/bootstrap/variables.less';", ".less", AppDomain.CurrentDomain.BaseDirectory)
I'll try to do a pull request soon. I hope this helps people looking to support dynamic LESS content with imports.