ASP.NET Bundles, как отключить минификацию

185

Я имею debug="true"в обоих своих web.config (s) , и я просто не хочу минимизировать свои пакеты, но ничего, что я делаю, кажется, отключить его. Я пробовал enableoptimisations=false, вот мой код:

//Javascript
bundles.Add(new ScriptBundle("~/bundles/MainJS")
            .Include("~/Scripts/regular/lib/mvc/jquery.validate.unobtrusive.js*")
            .Include("~/Scripts/regular/lib/mvc/jquery.validate*")
            .Include("~/Scripts/regular/lib/bootstrap.js")
            .IncludeDirectory("~/Scripts/regular/modules", "*.js", true)
            .IncludeDirectory("~/Scripts/regular/pages", "*.js", true)
            .IncludeDirectory("~/Scripts/regular/misc", "*.js", true));

//CSS
bundles.Add(new StyleBundle("~/bundles/MainCSS")
            .Include("~/Content/css/regular/lib/bootstrap.css*")
            .IncludeDirectory("~/Content/css/regular/modules", "*.css", true)
            .IncludeDirectory("~/Content/css/regular/pages", "*.css", true))
Baconbeastnz
источник
2
@ RickAnd-MSFT Запрос состоит в том, как включить связывание при отключенной минимизации. Использование web.config debug = true / false или EnableOptimizations только включает и выключает оба. Ответ Мартина Девиллера позволяет включить связывание, когда минификация отключена
guymid
2
также для меня .... для файла 'x.js' в комплекте убедитесь, что в папке НЕ находится файл 'x.min.js', в противном случае, хотя вы удалили преобразование минификации .. пакетирование выдаст 'pre' минимизированный файл, например, если у вас есть 'angular.js', тогда УДАЛИТЕ 'angular.min.js' ;-)
stooboo

Ответы:

137

Если у вас есть debug="true"в web.config и используется Scripts/Styles.Renderдля ссылки на пакеты на ваших страницах, что следует отключить как пакетирование и Минимизация. BundleTable.EnableOptimizations = falseвсегда будет отключать как связывание, так и минимизацию (независимо от флага отладки истина / ложь).

Возможно, вы не используете Scripts/Styles.Renderпомощников? Если вы напрямую предоставляете ссылки на пакет через BundleTable.Bundles.ResolveBundleUrl()вас, вы всегда получите минимизированный / пакетный контент.

Хао Кунг
источник
12
Исходя из этого ответа, я не уверен, как отключить только минификацию и оставить пакет на месте - это возможно?
Адам Тюльпер - MSFT
33
Чтобы сделать это, проще всего было бы заменить Script / StyleBundles для простых Пакетов, у которых нет Transform, установленной по умолчанию, это отключило бы минимизацию, но все еще связывало. Обратите внимание, что вам все равно придется включить EnableOptimizations в значение true для объединения.
Хао Кунг
2
также для меня .... для файла 'x.js' в комплекте убедитесь, что в папке НЕ находится файл 'x.min.js', в противном случае, хотя вы удалили преобразование минификации .. пакетирование выдаст 'pre' минимизированный файл, например, если у вас есть 'angular.js', тогда УДАЛИТЕ 'angular.min.js' ;-)
stooboo
1
@stooboo Это то, что исправило это для меня, но вам не нужно ничего удалять. Просто включите неминовый файл.
OneHoopyFrood
2
EnableOptimizations = false- где этот код принадлежит?
Алекс
158

Директивы условной компиляции - ваш друг:

#if DEBUG
            var jsBundle = new Bundle("~/Scripts/js");
#else
            var jsBundle = new ScriptBundle("~/Scripts/js");
#endif
Мартин Девиллерс
источник
16
На самом деле я думаю, что он прибил его - чтобы просто отключить минификацию, используйте Bundle согласно Hao, в противном случае используйте ScriptBundle, который связывает и минимизирует, нет?
Адам Тюльпер - MSFT
1
Это отличное решение, когда вы хотите ссылаться на пакет по его URI ссылки на пакет для таких вещей, как загрузка через RequireJS без использования собственной системы RequireJS связывания / минимизации.
Норман Х
1
Я вижу такие вещи, как Адам, я понимаю ScriptBundle как улучшенный Bundle, поэтому, так как вы хотите добавить базовую ссылку (без особых постопераций), Bundle кажется мне хорошим способом отключить минимизацию для определенного пакета.
Чарльз Гетье
6
@ RickAnd-MSFT Я думаю, вы неправильно понимаете цель этого кода, который позволяет связывать + нет минимизации в режиме отладки и связывать + минимизировать в режиме выпуска. Использование web.config debug = true / false или EnableOptimizations только включает и выключает оба. Я прочитал ваш комментарий и отклонил это решение Мартина, только чтобы выяснить, что это действительно очень хороший способ связывания без минимизации
guymid
-1 это «решение» в лучшем случае является пробелом. На самом деле, даже если это работает, это приводит к очень неприемлемому коду. Но это не самое страшное. Использование «Bundle» приводит к тому, что ресурсы передаются сервером с типом mime, установленным в «text / html» вместо «text / javascript». Если вы применяете этот подход для объединения CSS-файлов, вы играете с огнем в режиме отладки. Не. Просто не надо. Смотрите мой ответ для более здорового подхода, который работает в производственных сборках.
XDS
89

Чтобы отключить связывание и минимизацию, просто поместите этот файл .aspx (это отключит оптимизацию, даже если debug=trueв web.config )

vb.net:

System.Web.Optimization.BundleTable.EnableOptimizations = false

C # .NET

System.Web.Optimization.BundleTable.EnableOptimizations = false;

Если вы положите EnableOptimizations = trueэто будет связывать и минимизировать, даже если debug=trueв web.config

Мануэл
источник
2
Это единственное, что исправило проблему для меня. У меня было debug="true"и право, Script.Renderно оно все равно не работало. Также обратите внимание, что это не приведет к серверу каких-либо файлов .min.js, поэтому обязательно включайте незавершенные копии кода зависимости.
OneHoopyFrood
2
@TCC: я ошибаюсь, думая, что синтаксис vb.net должен иметь заглавную False?
jeremysawesome
@jeremysawesome о, да, я думаю, что это правильно, хорошая мысль :-) Я не программист VB очень часто, поэтому я даже не заметил ...
TCC
1
Первая строка должна быть "... даже если debug = false" нет?
UnionP
2
vb.Net не волнует регистр, False = false, например .tostring () = .toString ()
Мануэль
68

Вы можете отключить минификацию в ваших пакетах, просто очистив свои преобразования.

var scriptBundle = new ScriptBundle("~/bundles/scriptBundle");
...
scriptBundle.Transforms.Clear();

Лично я нашел это полезным, когда хотел объединить все мои скрипты в один файл, но мне нужно было удобочитаемость на этапах отладки.

muglio
источник
1
-1 Здесь будут драконы: Срыв JsMinifier / CssMinifier также срывает внутренний механизм, который устанавливает тип mime для «text / css» или «text / javascript». Это не вызывает проблем в режиме отладки / выпуска, но приводит к хаосу в css-комплектах в контексте опубликованных сборок (также как и в реальном времени): Chrome и firefox отказываются загружать упомянутые css-комплекты, заявляя, что их mime-типы установлены на «text / html» вместо «text / css». С js-bundles дела идут как-то, но в лучшем случае это сложно сделать js-bundle как text / html (<- серьезно?). Смотрите мой ответ для правильного подхода.
XDS,
28

Я перепробовал многие из этих предложений, но, казалось, что сработало. Я потратил немало часов, чтобы узнать, что это была моя ошибка:

@Scripts.Render("/bundles/foundation")

Это всегда сводило меня к минимуму и в комплекте Javascript, независимо от того, что я пытался. Вместо этого я должен был использовать это:

@Scripts.Render("~/bundles/foundation")

Дополнительный '~' сделал это. Я даже удалил его снова только в одном случае, чтобы посмотреть, действительно ли это так. Это было ... надеюсь, я смогу сэкономить хотя бы одному человеку часы, которые я потратил на это.

Ник
источник
Ух ты, я схожу с ума за последние 3 часа из-за этого ...
Бодох
24

Объедините несколько ответов, это работает для меня в ASP.NET MVC 4.

        bundles.Add(new ScriptBundle("~/Scripts/Common/js")
            .Include("~/Scripts/jquery-1.8.3.js")
            .Include("~/Scripts/zizhujy.com.js")
            .Include("~/Scripts/Globalize.js")
            .Include("~/Scripts/common.js")
            .Include("~/Scripts/requireLite/requireLite.js"));

        bundles.Add(new StyleBundle("~/Content/appLayoutStyles")
            .Include("~/Content/AppLayout.css"));

        bundles.Add(new StyleBundle("~/Content/css/App/FunGrapherStyles")
            .Include("~/Content/css/Apps/FunGrapher.css")
            .Include("~/Content/css/tables.css"));

#if DEBUG
        foreach (var bundle in BundleTable.Bundles)
        {
            bundle.Transforms.Clear();
        }
#endif
Джефф Тиан
источник
21

Существует также несколько простых способов управления минификацией (и другими функциями) вручную. Это новый преобразователь CssMinify (), использующий, например:

// this is in case when BundleTable.EnableOptimizations = false;
var myBundle = new StyleBundle("~/Content/themes/base/css")
    .Include("~/Content/themes/base/jquery.ui.core.css" /* , ... and so on */);
myBundle.Transforms.Add(new CssMinify());
bundles.Add(myBundle);

// or you can remove that transformer in opposite situation
myBundle.Transforms.Clear();

Это удобно, когда вы хотите иметь какую-то специальную часть связок только для минимизации. Допустим, вы используете некоторые стандартные (jQuery) стили, которые становятся у вас под ногами (принимая на себя множество чрезмерных запросов браузера), но вы хотите, чтобы ваша таблица стилей оставалась неизменной. (То же самое - с javascript).

Агат
источник
13

Я объединил несколько ответов, данных другими в этом вопросе, чтобы найти другое альтернативное решение.

Цель: всегда связывать файлы, отключить минимизацию JS и CSS в случае, если<compilation debug="true" ... /> и всегда применять пользовательское преобразование к комплекту CSS.

Мое решение :

1) В web.config : <compilation debug="true" ... />

2) В методе Global.asax Application_Start () :

 protected void Application_Start() {
     ...
     BundleTable.EnableOptimizations = true; // Force bundling to occur

     // If the compilation node in web.config indicates debugging mode is enabled
     // then clear all transforms. I.e. disable Js and CSS minification.
     if (HttpContext.Current.IsDebuggingEnabled) {
         BundleTable.Bundles.ToList().ForEach(b => b.Transforms.Clear());
     }

      // Add a custom CSS bundle transformer. In my case the transformer replaces a
      // token in the CSS file with an AppConfig value representing the website URL
      // in the current environment. E.g. www.mydevwebsite in Dev and
      // www.myprodwebsite.com in Production.
      BundleTable.Bundles.ToList()
          .FindAll(x => x.GetType() == typeof(StyleBundle))
          .ForEach(b => b.Transforms.Add(new MyStyleBundleTransformer()));
     ...
}
Винс Хорст
источник
7

Если для следующего свойства установлено значение false, оно отключит как связывание, так и минимизацию.

В файле Global.asax.cs добавьте строку, как указано ниже

protected void Application_Start()
{
    System.Web.Optimization.BundleTable.EnableOptimizations = false;
}
marvelTracker
источник
Я просто не понимаю, почему мои меньшие файлы преобразуются в css, когда у меня отключена эта функция? Когда я включаю оптимизацию, связывание меньшего количества файлов больше не работает.
FrenkyB
5

Вот как отключить минификацию для каждого пакета:

bundles.Add(new StyleBundleRaw("~/Content/foobarcss").Include("/some/path/foobar.css"));
bundles.Add(new ScriptBundleRaw("~/Bundles/foobarjs").Include("/some/path/foobar.js"));

Sidenote: пути, используемые для ваших пакетов, не должны совпадать с реальными путями в ваших опубликованных сборках, иначе ничего не будет работать. Также убедитесь, что вы не используете .js, .css и / или '.' и '_' в любом месте имени пакета. Сохраняйте имя как можно более простым и понятным, как в примере выше.

Вспомогательные классы показаны ниже. Обратите внимание, что для обеспечения устойчивости этих классов в будущем мы хирургическим путем удаляем минимизирующие экземпляры js / css вместо использования .clear (), а также вставляем преобразование типа mime-type-setter, без которого производственные сборки неизбежно сталкиваются с проблемами, особенно когда это происходит для правильной передачи css-пакетов (Firefox и Chrome отклоняют css-пакеты с mime-type, установленным в «text / html», который используется по умолчанию):

internal sealed class StyleBundleRaw : StyleBundle
{
        private static readonly BundleMimeType CssContentMimeType = new BundleMimeType("text/css");

        public StyleBundleRaw(string virtualPath) : this(virtualPath, cdnPath: null)
        {
        }

        public StyleBundleRaw(string virtualPath, string cdnPath) : base(virtualPath, cdnPath)
        {
                 Transforms.Add(CssContentMimeType); //0 vital
                 Transforms.Remove(Transforms.FirstOrDefault(x => x is CssMinify)); //0
        }
        //0 the guys at redmond in their infinite wisdom plugged the mimetype "text/css" right into cssminify    upon unwiring the minifier we
        //  need to somehow reenable the cssbundle to specify its mimetype otherwise it will advertise itself as html and wont load
}

internal sealed class ScriptBundleRaw : ScriptBundle
{
        private static readonly BundleMimeType JsContentMimeType = new BundleMimeType("text/javascript");

        public ScriptBundleRaw(string virtualPath) : this(virtualPath, cdnPath: null)
        {
        }

        public ScriptBundleRaw(string virtualPath, string cdnPath) : base(virtualPath, cdnPath)
        {
                 Transforms.Add(JsContentMimeType); //0 vital
                 Transforms.Remove(Transforms.FirstOrDefault(x => x is JsMinify)); //0
        }
        //0 the guys at redmond in their infinite wisdom plugged the mimetype "text/javascript" right into jsminify   upon unwiring the minifier we need
        //  to somehow reenable the jsbundle to specify its mimetype otherwise it will advertise itself as html causing it to be become unloadable by the browsers in published production builds
}

internal sealed class BundleMimeType : IBundleTransform
{
        private readonly string _mimeType;

        public BundleMimeType(string mimeType) { _mimeType = mimeType; }

        public void Process(BundleContext context, BundleResponse response)
        {
                 if (context == null)
                          throw new ArgumentNullException(nameof(context));
                 if (response == null)
                          throw new ArgumentNullException(nameof(response));

         response.ContentType = _mimeType;
        }
}

Чтобы все это работало, вам нужно установить (через nuget):

WebGrease 1.6.0+ Microsoft.AspNet.Web.Optimization 1.1.3+

И ваш web.config должен быть обогащен так:

<runtime>
       [...]
       <dependentAssembly>
        <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-x.y.z.t" newVersion="x.y.z.t" />
       </dependentAssembly>
       <dependentAssembly>
              <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-x.y.z.t" newVersion="x.y.z.t" />
       </dependentAssembly>
        [...]
</runtime>

<!-- setting mimetypes like we do right below is absolutely vital for published builds because for some reason the -->
<!-- iis servers in production environments somehow dont know how to handle otf eot and other font related files   -->
</system.webServer>
        [...]
        <staticContent>
      <!-- in case iis already has these mime types -->
      <remove fileExtension=".otf" />
      <remove fileExtension=".eot" />
      <remove fileExtension=".ttf" />
      <remove fileExtension=".woff" />
      <remove fileExtension=".woff2" />

      <mimeMap fileExtension=".otf" mimeType="font/otf" />
      <mimeMap fileExtension=".eot" mimeType="application/vnd.ms-fontobject" />
      <mimeMap fileExtension=".ttf" mimeType="application/octet-stream" />
      <mimeMap fileExtension=".woff" mimeType="application/font-woff" />
      <mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
      </staticContent>

      <!-- also vital otherwise published builds wont work  https://stackoverflow.com/a/13597128/863651  -->
      <modules runAllManagedModulesForAllRequests="true">
         <remove name="BundleModule" />
         <add name="BundleModule" type="System.Web.Optimization.BundleModule" />
      </modules>
      [...]
</system.webServer>

Обратите внимание, что вам, возможно, придется предпринять дополнительные шаги, чтобы заставить ваши css-связки работать с точки зрения шрифтов и т. Д. Но это другая история.

XDS
источник
4

Просто чтобы дополнить уже предоставленные ответы, если вы также хотите НЕ минимизировать / обфусцировать / объединять НЕКОТОРЫЕ файлы, в то же время допуская полное объединение и минимизацию для других файлов, лучшим вариантом является использование пользовательского средства визуализации, которое будет считывать содержимое определенного пакета. (s) и отображать файлы на странице, а не отображать виртуальный путь пакета. Я лично требовал этого, потому что IE 9 стоил $ *% @ кровати, когда мои CSS-файлы были связаны даже с выключенным минимизацией .

Большое спасибо этой статье , которая дала мне отправную точку для кода, который я использовал для создания CSS-рендерера, который отображал бы файлы для CSS, но все же позволял системе отображать мои javascript-файлы в связке / минимизации / запутывания.

Создан статический вспомогательный класс:

using System;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;

namespace Helpers
{
  public static class OptionalCssBundler
  {
    const string CssTemplate = "<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />";

    public static MvcHtmlString ResolveBundleUrl(string bundleUrl, bool bundle)
    {
      return bundle ? BundledFiles(BundleTable.Bundles.ResolveBundleUrl(bundleUrl)) : UnbundledFiles(bundleUrl);
    }

    private static MvcHtmlString BundledFiles(string bundleVirtualPath)
    {
      return new MvcHtmlString(string.Format(CssTemplate, bundleVirtualPath));
    }

    private static MvcHtmlString UnbundledFiles(string bundleUrl)
    {
      var bundle = BundleTable.Bundles.GetBundleFor(bundleUrl);

      StringBuilder sb = new StringBuilder();
      var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);

      foreach (BundleFile file in bundle.EnumerateFiles(new BundleContext(new HttpContextWrapper(HttpContext.Current), BundleTable.Bundles, bundleUrl)))
      {
        sb.AppendFormat(CssTemplate + Environment.NewLine, urlHelper.Content(file.VirtualFile.VirtualPath));
      }

      return new MvcHtmlString(sb.ToString());
    }

    public static MvcHtmlString Render(string bundleUrl, bool bundle)
    {
      return ResolveBundleUrl(bundleUrl, bundle);
    }
  }

}

Затем в файле макета бритвы:

@OptionalCssBundler.Render("~/Content/css", false)

вместо стандартного:

@Styles.Render("~/Content/css")

Я уверен, что создание необязательного рендерера для файлов javascript не потребует особых усилий для обновления этого помощника.

Джеймс Эби
источник
1
Работает хорошо. Если вы хотите, чтобы URL обновлялись при обновлении файлов, вы можете изменить их CssTemplateна что-то вроде "<link href=\"{0}?f={1}\" rel=\"stylesheet\" type=\"text/css\" />"и изменить sb.AppendFormatстроку на что-то вродеsb.AppendFormat(CssTemplate + Environment.NewLine, urlHelper.Content(file.VirtualFile.VirtualPath), System.IO.File.GetLastWriteTimeUtc(HttpContext.Current.Server.MapPath(file.IncludedVirtualPath)).Ticks);
franzo
Правда, мы сделали что-то подобное на работе. У нас была открытая статическая строка с именем JSVersion, которую мы поместили в класс Global.asax, который извлекал maj / min / build / rev исполняемой сборки. Затем мы ссылались на него так: <script type = "text / javascript" src = "Scripts / jsfile_name.js <% = Global.JSVersion%>"> </ script>
Джеймс Эби,
3

Ищи EnableOptimizations ключевому слову в вашем проекте

Так что если вы найдете

BundleTable.EnableOptimizations = true;

включи это false.

Би Джей Патель
источник
2
Это отключает минификацию, но также полностью отключает пакетирование, что, я думаю, должно быть отмечено.
Джон Павек
1

Если вы используете CSS-преобразование LESS / SASS, есть опция, useNativeMinificationкоторая может быть установлена ​​в false, чтобы отключить минимизацию (в web.config). Для моих целей я просто изменяю его здесь, когда мне нужно, но вы можете использовать преобразования web.config, чтобы всегда включать его в сборке релиза или, возможно, найти способ изменить его в коде.

<less useNativeMinification="false" ieCompat="true" strictMath="false"
      strictUnits="false" dumpLineNumbers="None">

Совет: весь смысл этого заключается в том, чтобы просмотреть ваш CSS, что вы можете сделать в инструментах проверки браузера или просто открыв файл. Когда пакетирование включено, имя файла изменяется при каждой компиляции, поэтому я помещаю следующее в верхней части моей страницы, чтобы я мог ежедневно просматривать скомпилированный CSS-файл в новом окне браузера при каждом его изменении.

@if (Debugger.IsAttached) 
{
    <a href="@Styles.Url(ViewBag.CSS)" target="css">View CSS</a>
}

это будет динамический URL что-то вроде https://example.com/Content/css/bundlename?v=UGd0FjvFJz3ETxlNN9NVqNOeYMRrOkQAkYtB04KisCQ1


Обновление: я создал преобразование web.config, чтобы установить для него значение true во время развертывания / сборки выпуска

  <bundleTransformer xmlns="http://tempuri.org/BundleTransformer.Configuration.xsd">
    <less xdt:Transform="Replace" useNativeMinification="true" ieCompat="true" strictMath="false" strictUnits="false" dumpLineNumbers="None">
      <jsEngine name="MsieJsEngine" />
    </less>
  </bundleTransformer>
Simon_Weaver
источник
1
Имя файла НЕ изменяется при каждой компиляции. Он основан на содержимом файла, поэтому он изменяется при каждом изменении файла.
Джим Раден
1

Это может оказаться полезным для кого - то в будущем , так как новые рамки, когда установка через VS, получает значение по умолчанию web.config, web.Debug.configи web.Release.config. В web.release.configвы найдете эту строку:

<compilation xdt:Transform="RemoveAttributes(debug)" />

казалось, это отменяет любые встроенные изменения, которые я сделал. Я прокомментировал эту строку, и мы подливались (с точки зрения просмотра не минимизированного кода в сборке "релиза")

Mutmatt
источник