11

我现在感觉有点卡住了。首先我用nuget

安装包 Bootstrap.less

安装包无点

然后,如Rick Anderson 的博客文章中关于在 asp.net mvc 中捆绑和缩小所示,我创建了一个 LessTransform-Class。我设置了 2 个几乎为空的 .less 文件并创建了一个新的捆绑包来打包它们......

    var lessBundle = new Bundle("~/MyLess").IncludeDirectory("~/Content/MyLess", "*.less", true);
    lessBundle.Transforms.Add(new LessTransformer());
    lessBundle.Transforms.Add(new CssMinify());
    bundles.Add(lessBundle);

效果很好。然后我在主 bootstrap.less 文件中添加了一个新的 StyleBundle(它基本上使用 @import 来包含 bootstrap.less 提供的所有其他 .less 文件)......

    bundles.Add(new StyleBundle("~/Bootstrap").Include("~/Content/Bootstrap/less/bootstrap.less"));

和引导 JavaScript 的 ScriptBundle ......

    bundles.Add(new ScriptBundle("~/bundles/Bootstrap").Include("~/Scripts/bootstrap/js/bootstrap-*"));

包括所有已发布的 bootstrap-*.js 文件和 TADAA 一切正常。CSS 已编译,包括所有导入的 JavaScript 文件均已正确加载。

但是......所有这些只适用于开发模式

    <compilation debug="true" targetFramework="4.5"/>

一旦我禁用调试以查看捆绑到一个文件中并且缩小是否正常工作,我就会遇到问题。

捆绑过程似乎无法将所有这些 .less 文件导入 bootstrap.less

/* Minification failed. Returning unminified contents.
(11,1): run-time error CSS1019: Unexpected token, found '/'
(11,2): run-time error CSS1019: Unexpected token, found '/'
(12,1): run-time error CSS1031: Expected selector, found '@import'
(12,1): run-time error CSS1025: Expected comma or open brace, found '@import'
(12,27): run-time error CSS1019: Unexpected token, found '/'
(12,28): run-time error CSS1019: Unexpected token, found '/'

 ... here go many many lines like these 

(60,25): run-time error CSS1019: Unexpected token, found ';'
(62,1): run-time error CSS1019: Unexpected token, found '/'
(62,2): run-time error CSS1019: Unexpected token, found '/'
(63,1): run-time error CSS1031: Expected selector, found '@import'
(63,1): run-time error CSS1025: Expected comma or open brace, found '@import'
(63,27): run-time error CSS1019: Unexpected token, found '/'
(63,28): run-time error CSS1019: Unexpected token, found '/'
: run-time error CSS1067: Unexpected end of file encountered
 */
/*!
 * Bootstrap v2.3.1 
 *
 * Copyright 2012 Twitter, Inc
 * Licensed under the Apache License v2.0
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Designed and built with all the love in the world @twitter by @mdo and @fat.
 */

// Core variables and mixins
@import "variables.less"; // Modify this for custom colors, font-sizes, etc
@import "mixins.less";

... and the rest of the original bootstrap.less... no style definitions

看看缩小的 bootstrap.javascript 包也让我感到困惑。在开发中加载页面后没有问题,现在在谷歌中捆绑和缩小 bootstrap.javascript 后,JavaScript 控制台状态

Uncaught TypeError: Cannot read property 'Constructor' of undefined

我查看了几个似乎与我的问题密切相关的主题,我尝试了一些事情,但到目前为止没有成功。

非常感谢任何可以了解我的情况并指出我遗漏或做错了什么的人。最好的问候,英戈

4

4 回答 4

10

如果您想将引导程序用作较少文件,并且不想再担心在您的开发机器和生产机器上捆绑和缩小,您可以考虑使用以下方法。

注意:如果您只在启用调试的情况下使用 Less-Files,则不需要所有这些;但是,只要您希望您的应用程序在 Windows Azure 这样的生产服务器上运行,并且仍然希望只修改较少的文件而不必关心捆绑和缩小过程......那么......那么这种方法将工作

因此,为了解决我觉得有点卡住的问题,我不得不以不同的方式解决问题,并且不得不修改(参见后面的修改 2)我想拥有的“BundleSource”。

所以不要忘记阅读靠近这个答案底部的第二个修改/警告!


修改 1)

因此,工作的第一个也是更大的部分是让无引导文件的捆绑工作。为了做到这一点,我冒昧地分叉了我在网上找到的一段代码(如果你只需要一个更少的文件包)本身就解决了我的问题......除非你可能想要使用或能够使用具有多个基本目录的多个较少捆绑...所以我实际上找到了对我有很大帮助的方法...

... 因此,我非常感谢Kristof Claes 的博客条目“使用 ASP.NET 捆绑和压缩 LESS 文件”,我偶然而高兴地偶然发现。

像我一样,他尝试使用 Scott Hanselman 在演讲中展示的 LessMinify.cs 来处理 1 个 LESS 文件,而不是仅仅将每个文件捆绑在一个充满 LESS 文件的目录中。

但正如他在博客条目中所展示的那样,他必须稍微扩展整个捆绑程序。这样,他提出的解决方案可以捆绑 1 个更少的文件,该文件使用导入来加载其他更少的文件。但是当他静态实现添加到源目录的路径时,可以在其中找到较少的文件......无论您定义哪个较少的捆绑包,都必须在同一目录中选择一个较少的文件......

这就是我冒昧地进一步扩展他的解决方案的地方。我创建了一个文件 LessBundling.cs,内容如下:

using dotless.Core.configuration;
using dotless.Core.Input;
using MvcApplication2.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Web;
using System.Web.Hosting;
using System.Web.Optimization;

namespace MvcApplication2.Extensions
{
    // create Less-Minifier (use Type to define source directory of less files [see below at BootstrapFileReader])
    public class LessMinify<TFileReader> : CssMinify
        where TFileReader : IFileReader
    {
        public LessMinify() {}

        public override void Process(BundleContext context, BundleResponse response)
        {
            var config = new DotlessConfiguration()
            { 
                MinifyOutput = true,
                ImportAllFilesAsLess = true,
                CacheEnabled = false,
                LessSource = typeof(TFileReader)
            };

            response.Content = dotless.Core.Less.Parse(response.Content, config);
            base.Process(context, response);
        }
    }

    // create a LessStyleBundler to allow initializing LessBundle with a single less file that uses imports
    public class LessStyleBundle<TFileReader> : Bundle
        where TFileReader : IFileReader
    {
        public LessStyleBundle(string virtualPath)
            : base(virtualPath, new LessMinify<TFileReader>()) {}

        public LessStyleBundle(string virtualPath, string cdnPath)
            : base(virtualPath, cdnPath, new LessMinify<TFileReader>()) { }
    }

    // create abstract VirtualFileReader from dotless-IFileReader as a Base for localized 
    internal abstract 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);
        }


        public string GetFullPath(string path)
        {
            return  HostingEnvironment.MapPath(SourceDirectory + path);
        }

        public abstract string SourceDirectory {get;}
        // implement to return Path to location of less files
        // e. g. return "~/Content/bootstrap/less/";
    }

    // create BootstrapFileReader overwriting the Path where to find the Bootstrap-Less-Files
    internal sealed class BootstrapFileReader : VirtualFileReader
    {
        public override string SourceDirectory 
        {
            get { return "~/Content/bootstrap/less/"; }
        }
    }

}

那么这实际上是做什么的呢?

  1. LessMinify 扩展了 CssMinify 类,因此带来了缩小 css 文件所需的一切
    • 与“通常”捆绑的重要区别在于,您创建了一个新的 Dotless-Configuration,其 LessSource 定义为 typeof(TFileReader) ...
    • 通过使用 <TFileReader> 您可以定义一个包含源目录的类,bundler/minifier 将在其中查找要考虑的较少文件
  2. LessStyleBundle 扩展了 Bundle,因此带来了捆绑文件所需的一切
    • 在这个类中,我再次使用 TFileReader,因为这是 LessMinify(er) 将被实例化的地方
  3. VirtualFileReader 实现了 IFileReader,它是一个无点接口,定义了解析较少文件所需的所有方法,并提供在何处查找要导入的文件的信息
    • 为了扩展 Kristof 对问题的解决方案,我添加了抽象属性 SourceDirectory... 要求我还创建 VirtualFileReader 抽象类

现在通过该设置,您可以根据需要创建任意数量的 LessFileReader。你只需要扩展抽象的 VirtualFileReader 就可以了

  1. BootstrapFileReader 扩展 VirtualFileReader
    • BootstrapFileReader 的唯一目的是为 SourceDirectory 提供一个属性获取器,bundler/minifier 将在其中找到要导入的较少文件

好吧,就我而言,Bootstraps Less-Files 位于 ~/Content/bootstrap/less 中,如果您安装“twitter.bootstrap.less”-nugget,这应该是默认位置。

如果您的应用程序中有另一个目录,其中包含一个较少的文件,该文件又具有多个导入,您只需创建一个扩展 VirtualFileReader 的新类并为 SourceDirectory 定义属性获取器以返回相应的路径

如果您想在生产环境中使用此捆绑方法实际捆绑和缩小文件,您只需将 LessStyleBundle 实例添加到 BundlerConfig.cs:

bundles.Add(new LessStyleBundle<BootstrapFileReader>("~/bundles/BootstrapCSS")
    .Include("~/Content/bootstrap/less/bootstrap.less"));

当然,您的 _Layout.cshtml 也应该知道准备好的捆绑包

@Styles.Render("~/bundles/BootstrapCSS")

修改 2)

现在我还必须添加小修改才能使其正常工作

在我第一次尝试捆绑 bootstrap.less 时,我使用了这个

bundles.Add(new LessStyleBundle<BootstrapFileReader>("~/Content/BootstrapCSS")
    .Include("~/Content/bootstrap/less/bootstrap.less"));

我想我会在 CSS/Less 的路由中使用 Content,在 Javascript 的路由中使用 Bundles。

但这不是开箱即用的。ASP.net 不允许创建以~/Content开头的 Bundle 。您将收到 403 授权失败。因此,最简单的解决方案是使用~/bundles代替:

bundles.Add(new LessStyleBundle<BootstrapFileReader>("~/bundles/BootstrapCSS")
    .Include("~/Content/bootstrap/less/bootstrap.less"));

由于这个问题没有很多真正的解决方案,如果您打算将 twitter bootstrap 集成到您的 asp.net mvc4 应用程序中,我希望这至少对你们中的一些人有所帮助。

最好的问候,英戈

于 2013-03-27T00:02:23.477 回答
3

我已经修改了 Ingo 解决方法以摆脱每个目录的自定义类。此外,我添加了适当的异常输出(因为否则所有异常都是静默的,并且在出现错误时您只会得到空文件)。

public class LessTransform : IItemTransform
{
    [ThreadStatic]
    internal static string CurrentParsedFileDirectory;


    public string Process (string includedVirtualPath, string input)
    {
        CurrentParsedFileDirectory = Path.GetDirectoryName (includedVirtualPath);

        var config = new DotlessConfiguration
        {
            MinifyOutput = false,
            CacheEnabled = false,
            MapPathsToWeb = true,
            ImportAllFilesAsLess = true,
            LessSource = typeof (VirtualFileReader),
            Logger = typeof (ThrowExceptionLogger)
        };

        return Less.Parse (input, config);
    }
}


internal class VirtualFileReader : IFileReader
{
    public bool UseCacheDependencies
    {
        get { return false; }
    }


    public byte[] GetBinaryFileContents (string fileName)
    {
        return File.ReadAllBytes (GetFullPath (fileName));
    }


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


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


    public string GetFullPath (string path)
    {
        if (string.IsNullOrEmpty (path))
            return string.Empty;

        return HostingEnvironment.MapPath (path[0] != '~' && path[0] != '/'
                                               ? Path.Combine (LessTransform.CurrentParsedFileDirectory, path)
                                               : path);
    }
}


public class ThrowExceptionLogger : Logger
{
    public ThrowExceptionLogger (LogLevel level) : base (level)
    {
    }


    protected override void Log (string message)
    {
        if (string.IsNullOrEmpty (message))
            return;

        if (message.Length > 100)
            message = message.Substring (0, 100) + "...";

        throw new LessTransformException (message);
    }
}


[Serializable]
public sealed class LessTransformException : Exception
{
    public LessTransformException (string message) : base (message)
    {
    }
}

用法:

bundles.Add (new StyleBundle ("~/styles-bundle/common")
    .Include ("~/content/bootstrap/bootstrap.less", new LessTransform ()));
于 2013-12-25T12:26:28.947 回答
2

我今天遇到了同样的问题,我找到了解决方法,但我也想要一个更好的解决方案。我还尝试使用 dotless 和自定义转换,就像你所拥有的那样。

解决方法:

预建事件:

"$(SolutionDir)packages\dotless.1.3.1.0\tool\dotless.compiler.exe" "$(ProjectDir)Content\less\bootstrap.less"

这将创建一个bootstrap.css文件,然后您可以将其包含为常规文件CSS而不是LESS.

这个解决方案并不理想,因为每次更新 dotless 时都必须更新构建事件,并且让包处理它也更干净。

于 2013-03-13T08:04:53.397 回答
0

我真的非常推荐安装WebEssentials 2012

它将从您的 .less 生成一个 css 文件和一个缩小的 css 文件,您可以改为引用 css。每次您对 .less 进行更改时,它都会自动更新 css,因此无需记住任何预构建步骤或任何东西......

安装 WebEssentials 时,您还将获得其他甜蜜的功能,例如 CoffeeScript、TypeScript 和 LESS 的预览。JSHint,自动缩小和更多“好东西”!

于 2013-06-25T08:46:15.200 回答