如何使用ASP.Net MVC 4在发布模式下捆绑LESS文件?

Gra*_*ark 24 bundle less asp.net-mvc-4

我正在尝试在我的web项目中使用LESS文件,并将MVC 4捆绑功能调用到dotLess库中以将LESS转换为CSS,然后缩小结果并将其提供给浏览器.

我在ASP.NET站点上找到了一个示例(在LESS,CoffeeScript,SCSS,Sass Bundling标题下).这给了我一个LessTransform看起来像这样的类:

public class LessTransform : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        response.Content = dotless.Core.Less.Parse(response.Content);
        response.ContentType = "text/css";
    }
}
Run Code Online (Sandbox Code Playgroud)

BundleConfig班上的这一行:

bundles.Add(new Bundle(
    "~/Content/lessTest", 
    new LessTransform(), 
    new CssMinify()).Include("~/Content/less/test.less"));
Run Code Online (Sandbox Code Playgroud)

最后我在_Layout.cshtml中有以下行<head>:

@Styles.Render("~/Content/lessTest")
Run Code Online (Sandbox Code Playgroud)

如果我将站点设置为调试模式,则会将其呈现给浏览器:

<link href="/Content/less/test.less" rel="stylesheet"/>
Run Code Online (Sandbox Code Playgroud)

应用.less文件中的规则,并在该链接后显示LESS已正确转换为CSS.

但是,如果我将网站置于发布模式,则会显示出来:

<link href="/Content/less?v=lEs-HID6XUz3s2qkJ35Lvnwwq677wTaIiry6fuX8gz01" rel="stylesheet"/>
Run Code Online (Sandbox Code Playgroud)

无法应用.less文件中的规则,因为在链接后出现IIS的404错误.

所以捆绑似乎出了问题.如何让它在发布模式下工作,或者如何找出确切的错误?

Dav*_*and 15

作为已接受答案的补充,我创建了一个LessBundle类,它是StyleBundle类的Less eqivalent.

LessBundle.cs代码是:

using System.Web.Optimization;

namespace MyProject
{
    public class LessBundle : Bundle
    {
        public LessBundle(string virtualPath) : base(virtualPath, new IBundleTransform[] {new LessTransform(), new CssMinify()})
        {

        }

        public LessBundle(string virtualPath, string cdnPath)
            : base(virtualPath, cdnPath, new IBundleTransform[] { new LessTransform(), new CssMinify() })
        {

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法类似于StyleBundle类,指定LESS文件而不是CSS文件.

将以下内容添加到BundleConfig.RegisterBundles(BundleCollection)方法:

bundles.Add(new LessBundle("~/Content/less").Include(
                 "~/Content/MyStyles.less"));
Run Code Online (Sandbox Code Playgroud)

更新

这种方法在关闭优化时工作正常,但是在打开优化时我遇到了一些小问题(使用CSS资源路径).经过一个小时研究这个问题,我发现我已经重新发明了轮子......

如果您确实需要我上面描述的LessBundle功能,请查看System.Web.Optimization.Less.

NuGet包可以在这里找到.


Emm*_*ook 12

似乎无点引擎需要知道当前处理的bundle文件的路径以解析@import路径.如果运行上面的进程代码,则当解析的.less文件导入的文件较少时,dotless.Core.Less.Parse()的结果为空字符串.

Ben Foster在这里的回答将通过首先读取导入的文件来解决这个问题:

导入文件和DotLess

更改LessTransform文件,如下所示:

public class LessTransform : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse bundle)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

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

        var bundleFiles = new List<FileInfo>();

        foreach (var bundleFile in bundle.Files)
        {
            bundleFiles.Add(bundleFile);

            SetCurrentFilePath(lessParser, bundleFile.FullName);
            string source = File.ReadAllText(bundleFile.FullName);
            content.Append(lessEngine.TransformToCss(source, bundleFile.FullName));
            content.AppendLine();

            bundleFiles.AddRange(GetFileDependencies(lessParser));
        }

        if (BundleTable.EnableOptimizations)
        {
            // include imports in bundle files to register cache dependencies
            bundle.Files = bundleFiles.Distinct();
        }

        bundle.ContentType = "text/css";
        bundle.Content = content.ToString();
    }

    /// <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, true, false);
    }

    /// <summary>
    /// Gets the file dependencies (@imports) of the LESS file being parsed.
    /// </summary>
    /// <param name="lessParser">The LESS parser.</param>
    /// <returns>An array of file references to the dependent file references.</returns>
    private IEnumerable<FileInfo> GetFileDependencies(Parser lessParser)
    {
        IPathResolver pathResolver = GetPathResolver(lessParser);

        foreach (var importPath in lessParser.Importer.Imports)
        {
            yield return new FileInfo(pathResolver.GetFullPath(importPath));
        }

        lessParser.Importer.Imports.Clear();
    }

    /// <summary>
    /// Returns an <see cref="IPathResolver"/> instance used by the specified LESS lessParser.
    /// </summary>
    /// <param name="lessParser">The LESS parser.</param>
    private IPathResolver GetPathResolver(Parser lessParser)
    {
        var importer = lessParser.Importer as Importer;
        var fileReader = importer.FileReader as FileReader;

        return fileReader.PathResolver;
    }

    /// <summary>
    /// Informs the LESS parser about the path to the currently processed file. 
    /// This is done by using a 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)
            throw new InvalidOperationException("Unexpected dotless importer type.");

        var fileReader = importer.FileReader as FileReader;

        if (fileReader == null || !(fileReader.PathResolver is ImportedFilePathResolver))
        {
            fileReader = new FileReader(new ImportedFilePathResolver(currentFilePath));
            importer.FileReader = fileReader;
        }
    }
}

public class ImportedFilePathResolver : IPathResolver
{
    private string currentFileDirectory;
    private string currentFilePath;

    public ImportedFilePathResolver(string currentFilePath)
    {
        if (string.IsNullOrEmpty(currentFilePath))
        {
            throw new ArgumentNullException("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)
    {
        if (filePath.StartsWith("~"))
        {
            filePath = VirtualPathUtility.ToAbsolute(filePath);
        }

        if (filePath.StartsWith("/"))
        {
            filePath = HostingEnvironment.MapPath(filePath);
        }
        else if (!Path.IsPathRooted(filePath))
        {
            filePath = Path.GetFullPath(Path.Combine(currentFileDirectory, filePath));
        }

        return filePath;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `bundle.Files`不是`List <FileInfo>`; 它是一个`List <BundleFile>`.这段代码对我不起作用. (7认同)