Empacotador que não inclui arquivos .min

261

Eu tenho um problema estranho com o empacotador mvc4 que não inclui arquivos com extensão .min.js

Na minha classe BundleConfig, declaro

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/Scripts/jquery")
        .Include("~/Scripts/jquery-1.8.0.js")
        .Include("~/Scripts/jquery.tmpl.min.js"));            
}

Na minha opinião, declaro

<html>
    <head>
    @Scripts.Render("~/Scripts/jquery")
    </head><body>test</body>
</html>

E quando processa, apenas processa

<html>
    <head>
         <script src="/Scripts/jquery-1.8.0.js"></script>
    </head>
    <body>test</body>
</html>

Se eu renomear o jquery.tmpl.min.js para jquery.tmpl.js (e atualizar o caminho no pacote configurável adequadamente), os dois scripts serão renderizados corretamente.

Existe alguma configuração que está fazendo com que ele ignore os arquivos '.min.js'?

Fatal
fonte
Estou usando o empacotador MVC 4 e está incluindo arquivos .min.js.
Eric J.
a versão RTM ou o RC? ele estava funcionando ok no RC para mim também
Fatal
10
A idéia é que, trabalhando no modo de depuração, que a versão "dev" sem minificação seja usada e, quando você estiver no modo não de depuração, que a versão minificada seja escolhida. Para vê-lo em ação, altere o valor de depuração do web.config de true para false.
Pieter Germishuys
28
em alguns casos, você não possui a versão não minificada do script. Eu poderia possivelmente compreendê-lo se ambos os arquivos existiu.
Fatal
1
É uma pena que funcione assim por padrão ... claro, o arquivo já pode estar minificado , mas acho que a Microsoft não viu o benefício de adicionar scripts pré-minificados a pacotes para propósitos de impedir o cache (o pequeno e agradável vparâmetro hash que é adicionado ao url, e muda quando o conteúdo do arquivo mudar)
nothingisnecessary

Respostas:

257

A solução que postei originalmente é questionável (é um truque sujo). O comportamento aprimorado foi alterado no pacote Microsoft.AspNet.Web.Optimization e o ajuste não funciona mais, conforme apontado por muitos comentaristas. No momento, não consigo reproduzir o problema com a versão 1.1.3 do pacote.

Consulte as fontes de System.Web.Optimization.BundleCollection (você pode usar o dotPeek por exemplo) para entender melhor o que você está prestes a fazer. Leia também a resposta de Max Shmelev .

Resposta original :

Renomeie .min.js para .js ou faça algo como

    public static void AddDefaultIgnorePatterns(IgnoreList ignoreList)
    {
        if (ignoreList == null)
            throw new ArgumentNullException("ignoreList");
        ignoreList.Ignore("*.intellisense.js");
        ignoreList.Ignore("*-vsdoc.js");
        ignoreList.Ignore("*.debug.js", OptimizationMode.WhenEnabled);
        //ignoreList.Ignore("*.min.js", OptimizationMode.WhenDisabled);
        ignoreList.Ignore("*.min.css", OptimizationMode.WhenDisabled);
    }

    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.IgnoreList.Clear();
        AddDefaultIgnorePatterns(bundles.IgnoreList);
        //NOTE: it's bundles.DirectoryFilter in Microsoft.AspNet.Web.Optimization.1.1.3 and not bundles.IgnoreList

        //...your code
     }
Pavel
fonte
4
Graças de mim também - assim que adicionar este à minha lista Gotcha MVC4 :)
Dan B
27
esse foi um longo momento, eles poderiam estar adicionando os arquivos min comentados com razão ou algo como resultado, agora toda a hora desperdiçada imaginando quem está roubando meus arquivos de script da saída.
precisa
5
De acordo com o comentário de Fatal no OP, esta solução acabará rednering referências duplicadas para as versões minificada e regular, se ambas existirem (por exemplo, jquery).
Danmiser 27/08/12
11
M $, quando somefile.min.js for explicitamente especificado ou quando apenas o arquivo .min.js existir, inclua apenas o arquivo .min.js! Caso contrário, basta aplicar o comportamento atual!
Adaptabi
3
É incrível que a classe real seja chamada "IgnoreList", mas deriva diretamente de Object. Sem LINQ, sem iteração. - msdn.microsoft.com/en-us/library/…
JP ten Berge
176

A Microsoft implica o seguinte comportamento (e eu prefiro segui-lo em meus projetos):

versão curta

  1. Você tem versões de depuração e minificadas de um script no seu projeto na mesma pasta:
    • script.js
    • script.min.js
  2. Você adiciona apenas script.js a um pacote no seu código.

Como resultado, você terá automaticamente o script.js incluído no modo DEBUG e o script.min.js no modo RELEASE .

versão longa

Você também pode ter a versão .debug.js . Nesse caso, o arquivo é incluído na seguinte prioridade no DEBUG:

  1. script.debug.js
  2. script.js

em LANÇAMENTO:

  1. script.min.js
  2. script.js

Nota

A propósito, o único motivo para ter versões .min de seus scripts no MVC4 é o caso em que a versão minificada não pode ser processada automaticamente. Por exemplo, o código a seguir não pode ser ofuscado automaticamente:

if (DEBUG) console.log("Debug message");

Em todos os outros casos, você pode usar apenas uma versão de depuração do seu script.

Max Shmelev
fonte
6
boa explicação, no entanto, o problema do OP era que alguns scripts ( jquery.tmpl) não tinham, não vieram, não foram baixados da versão não-mínima do arquivo. O bundler ignora os arquivos de script por completo, se ele não tem uma versão não-min no modo de depuração
Eonasdan
Concordo, boa explicação, mas não responde à pergunta de todos os OP.
18712 Diego
2
Versão curta não funcionou para mim. "script.js" seria incluído nesses dois tipos de versão. Alternei DEBUG / RELEASE e (quando olhei a fonte) 'script.js' foi o selecionado / renderizado.
user981375
4
user981375, você também precisa definir <compilation debug = "false" /> no arquivo web.config
Max Shmelev
5
Prefiro esta resposta porque é uma abordagem de "melhores práticas" e explica como as regras padrão do empacotador podem ser seguidas para atingir o mesmo objetivo.
James Reategui
5

Se tudo o que você tem é uma versão minificada de um arquivo, a solução mais simples que encontrei é copiar o arquivo minificado, remover .min do nome do arquivo copiado e referenciar o nome do arquivo não minificado em seu pacote.

Por exemplo, digamos que você comprou um componente js e eles forneceram um arquivo chamado some-lib-3.2.1.min.js. Para usar esse arquivo em um pacote configurável, faça o seguinte:

  1. Copie some-lib-3.2.1.min.js e renomeie o arquivo copiado para some-lib-3.2.1.js. Inclua os dois arquivos no seu projeto.

  2. Faça referência ao arquivo não minificado em seu pacote configurável, desta forma:

    bundles.Add(new ScriptBundle("~/bundles/libraries").Include(
        "~/Scripts/some-lib-{version}.js"
    ));
    

Só porque o arquivo sem 'min' no nome é realmente minificado não deve causar nenhum problema (além do fato de ser essencialmente ilegível). É usado apenas no modo de depuração e é gravado como um script separado. Quando não estiver no modo de depuração, o arquivo min pré-compilado deve ser incluído no seu pacote.

joelfp
fonte
4

Eu encontrei uma boa solução que funciona pelo menos no MVC5, você pode simplesmente usar em Bundlevez de ScriptBundle. Não possui o comportamento inteligente de ScriptBundleque não gostamos (ignorando .min etc.) neste caso. Na minha solução, uso Bundlepara scripts de festa em 3D com arquivos .min e .map e uso ScriptBundlepara o nosso código. Não notei nenhuma desvantagem em fazê-lo. Para fazê-lo funcionar desta maneira, você precisará adicionar o arquivo original, por exemplo, angular.js, e ele carregará angular.js na depuração e agrupará o angular.min.js no modo de lançamento.

Ilya Chernomordik
fonte
Parece não funcionar quando as otimizações estão desativadas ( ScriptTable.EnableOptimizations = false). Os caminhos de script que contêm um padrão não são renderizados (por exemplo ~/Scripts/thirdpartylib/*.js). Ele faz o trabalho quando EnableOptimizations = true, mas o mesmo acontece ScriptBundle.
Steven Liekens
Também o uso com false (durante o desenvolvimento) e não tenho problemas que você descreve, por isso pode ser outra coisa que está afetando isso para você. Você também precisa fazer o IncludeDirectory em vez de incluir para que o padrão funcione.
Ilya Chernomordik
Tem certeza de que está processando a versão ".min.js" do seu arquivo? Você está usando pacotes System.Web.Optimizationsconfiguráveis do namespace ou do pacote nuget Microsoft.Web.Optimizations?
9158 Steven Steckens
Eu uso System.Web.Optimization e verifiquei que ele renderiza a versão mínima, mas eu descobri que não uso o IncludeDirectory, mas seria estranho se isso não funcionasse com a versão mínima ... Como o IncludeDirectory não é o suficiente para mim, faço uma varredura personalizada e adiciono todo o filtro usando a opção Incluir, para que o padrão e o IncludeDirectory não funcionem corretamente lá, embora seja um pouco estranho.
Ilya Chernomordik
1
Não, o problema é duplo: .min.jsexiste apenas um arquivo e o *.jspadrão não corresponde aos arquivos que terminam em .min.js.
22916 Steven Stevkens
3

Para renderizar *.min.jsarquivos, você deve desativar BundleTable.EnableOptimizations, que é uma configuração global que se aplica a todos os pacotes configuráveis.

Se você deseja ativar otimizações apenas para pacotes configuráveis ​​específicos, é possível criar seu próprio ScriptBundletipo que ativa temporariamente otimizações ao enumerar arquivos no pacote configurável.

public class OptimizedScriptBundle : ScriptBundle
{
    public OptimizedScriptBundle(string virtualPath)
        : base(virtualPath)
    {
    }

    public OptimizedScriptBundle(string virtualPath, string cdnPath)
        : base(virtualPath, cdnPath)
    {
    }

    public override IEnumerable<BundleFile> EnumerateFiles(BundleContext context)
    {
        if (context.EnableOptimizations)
            return base.EnumerateFiles(context);
        try
        {
            context.EnableOptimizations = true;
            return base.EnumerateFiles(context);
        }
        finally
        {
            context.EnableOptimizations = false;
        }
    }
}

Use em OptimizedScriptBundlevez de ScriptBundlepara pacotes configuráveis ​​cujo arquivo minificado deve sempre ser usado, independentemente de existir um arquivo não minificado.

Exemplo da interface do usuário do Kendo para o ASP.NET MVC, que é distribuído como uma coleção de apenas arquivos minificados.

bundles.Add(new OptimizedScriptBundle("~/bundles/kendo")
        .Include(
            "~/Scripts/kendo/kendo.all.*",
            "~/Scripts/kendo/kendo.aspnetmvc.*",
            "~/Scripts/kendo/cultures/kendo.*",
            "~/Scripts/kendo/messages/kendo.*"));
Steven Liekens
fonte
Me deparei com alguns scripts ausentes em uma ação de publicação de produção e, pensando que era um problema do MVC, encontrei esta resposta .. eis que o kendo está envolvido. Tendo trabalhado com ele por muito tempo, eu faria qualquer coisa para ficar longe de kendo
Felipe
@ Felipe Eu estava na mesma situação e foi por isso que escrevi esta resposta. Kendo é horrível. Espero que meu exemplo seja útil.
Steven Liekens
2

Para o meu caso, eu estava usando a biblioteca Knockout.js (maravilhosa!), Que vem nas versões Debug / Non:

"~/Scripts/knockout-{Version}.js"
"~/Scripts/knockout-{Version}.Debug.js"

Para fazer isso funcionar, incluí "Knockout- {Version} .js" (sem depuração) no meu Bundle e obtive o .debug. arquivo js no modo de depuração.

AcidPAT
fonte
1

Uma maneira fácil apenas renomeie o arquivo .min, por exemplo, você tem abc.min.css do que apenas renomeie esse arquivo para abc_min.css e adicione-o ao seu pacote configurável. Eu sei que não é o caminho certo para fazê-lo, mas apenas uma solução temporária. obrigado e feliz codificação.

RK Sharma
fonte
1
Sempre que o nuget baixar o arquivo, você precisará renomear.
Anirudha Gupta
Eu sei que não é o caminho certo para fazê-lo, mas apenas uma solução temporária
RK Sharma
1
colocar esta linha está funcionando para mim // BundleTable.EnableOptimizations = true;
Anirudha Gupta
0

Os empacotadores têm muitos benefícios, verifique esta página MAS :

A plataforma Microsoft MVC4 considera que você possui pelo menos a versão minificada e a versão não minificada para cada Script ou Pacote de estilos (outros arquivos como Debug e vsdoc também estão disponíveis). Portanto, temos problemas em situações em que existe apenas um desses arquivos.

Você pode alterar o estado de depuração no arquivo web.config permanentemente para manipular a saída:

<compilation debug="false" targetFramework="4.0" />

Veja as alterações de saída! A filtragem de arquivos foi alterada. Para cumprir o objetivo, devemos mudar, ignorar a filtragem de casos que mudará a lógica da aplicação!

Amirhossein Mehrvarzi
fonte
1
Adicionar debug = "false" ainda não funciona para mim. min.js arquivos ainda não estão incluídos, embora eu limpar o Ignorelist bem ...
Moss
-21

Pessoal, eu simplesmente manteria isso até a Microsoft conseguir agir em conjunto

Tente isto

Em RegisterBundles, crie este pacote para o Kendo

bundles.Add(new StyleBundle("~/Content/kendo/css").Include(
                    "~/Content/kendo/2012.3.1121/kendo.common.min.css",
                     "~/Content/kendo/2012.3.1121/kendo.dataviz.min.css",
                      "~/Content/kendo/2012.3.1121/kendo.blueopal.min.css"
 ));

Em _Layout.cshtml, coloque isso:

@if (HttpContext.Current.IsDebuggingEnabled)
 { 
<link href="@Url.Content("~/Content/kendo/2012.3.1121/kendo.common.min.css")"      
rel="stylesheet"  type="text/css" />
<link href="@Url.Content("~/Content/kendo/2012.3.1121/kendo.dataviz.min.css")" 
rel="stylesheet" type="text/css" />   
<link href="@Url.Content("~/Content/kendo/2012.3.1121/kendo.blueopal.min.css")"    
rel="stylesheet" type="text/css" />
 }
 else
 {
     @Styles.Render("~/Content/kendo/css")   
 }

Dessa forma, obtemos o melhor dos pacotes em Produção e uma referência em Debug

Corrija-o quando a Microsoft corrigir o código MVC 4

user1819794
fonte
3
Não sou fã desta solução proposta. Agora você está tendo que manter o conjunto de scripts em (pelo menos) dois lugares
Fatal
Isso praticamente derrota o objetivo do pacote, você não acha?
Oliver
4
O empacotamento já funciona dessa maneira. Se você executar o projeto no modo de depuração, cada arquivo CSS será carregado individualmente, no entanto, quando você executar na versão, eles serão combinados e minificados em um. O código dentro do bloco if é idêntico ao que é renderizado na página automaticamente no modo de depuração.
Chad Levy