Bundler n'incluant pas les fichiers .min

261

J'ai un problème étrange avec le bundle mvc4 n'incluant pas les fichiers avec l'extension .min.js

Dans ma classe BundleConfig, je déclare

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

À mon avis, je déclare

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

Et quand ça rend, ça ne fait que rendre

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

Si je renomme jquery.tmpl.min.js en jquery.tmpl.js (et que je mets à jour le chemin d'accès dans le bundle en conséquence), les deux scripts sont rendus correctement.

Y a-t-il un paramètre de configuration qui fait qu'il ignore les fichiers «.min.js»?

Fatal
la source
J'utilise le bundle MVC 4 et il inclut des fichiers .min.js.
Eric J.
la version RTM ou la RC? ça fonctionnait bien dans la RC pour moi aussi
Fatal
10
L'idée est que travailler en mode débogage, que la version "dev" sans minification sera utilisée et lorsque vous êtes en mode non débogage, que la version minifiée soit choisie. Pour le voir en action, changez votre valeur de débogage web.config de true en false.
Pieter Germishuys
28
dans certains cas, vous n'avez pas la version non réduite du script. Je pourrais éventuellement le comprendre si les deux fichiers existaient.
Fatal
1
C'est une déception que cela fonctionne comme ça par défaut ... bien sûr, le fichier peut déjà être minifié , mais je pense que Microsoft n'a pas vu l'avantage d'ajouter des scripts prédéfinis aux bundles à des fins de contournement du cache (le joli petit vhachage de paramètre qui est ajouté à l'URL et change lorsque le contenu du fichier change)
rien n'est nécessaire

Réponses:

257

La solution que j'ai publiée à l'origine est discutable (c'est un hack sale). Le comportement modifié a changé dans le package Microsoft.AspNet.Web.Optimization et le réglage ne fonctionne plus, comme l'ont souligné de nombreux commentateurs. Pour le moment, je ne peux pas du tout reproduire le problème avec la version 1.1.3 du package.

Veuillez consulter les sources de System.Web.Optimization.BundleCollection (vous pouvez utiliser dotPeek par exemple) pour une meilleure compréhension de ce que vous êtes sur le point de faire. Lisez également la réponse de Max Shmelev .

Réponse originale :

Renommez .min.js en .js ou faites quelque chose comme

    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
la source
4
Merci de moi aussi - alors ajoutez ceci à ma liste de questions MVC4 :)
Dan B
27
ce fut un long moment wtf, ils auraient pu ajouter ces fichiers min commentés avec raison ou quelque chose en résultant, maintenant une heure entière gaspillée à se demander qui vole mes fichiers de script de la sortie.
Giedrius
5
Selon le commentaire de Fatal dans l'OP, cette solution finira par redéfinir les références en double pour les versions minifiées et régulières si elles existent toutes les deux (par exemple jquery).
danmiser
11
M $, lorsque somefile.min.js est explicitement spécifié, ou lorsque seul le fichier .min.js existe, alors n'incluez que le fichier .min.js! Sinon, appliquez simplement le comportement actuel!
Adaptabi
3
Incroyable que la classe actuelle soit appelée "IgnoreList", mais elle dérive directement d'Object. Pas de LINQ, pas d'itération. - msdn.microsoft.com/en-us/library/…
JP ten Berge
176

Microsoft implique le comportement suivant (et je préfère le suivre dans mes projets):

version courte

  1. Vous disposez à la fois de versions de débogage et de version réduite d'un script dans votre projet sous le même dossier:
    • script.js
    • script.min.js
  2. Vous ajoutez uniquement script.js à un ensemble dans votre code.

En conséquence, vous aurez automatiquement le script.js inclus en mode DEBUG et script.min.js en mode RELEASE .

version longue

Vous pouvez également avoir la version .debug.js . Dans ce cas, le fichier est inclus dans la priorité suivante dans DEBUG:

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

en version:

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

Remarque

Et d'ailleurs, la seule raison d'avoir une version .min de vos scripts dans MVC4 est le cas où la version minifiée ne peut pas être traitée automatiquement. Par exemple, le code suivant ne peut pas être masqué automatiquement:

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

Dans tous les autres cas, vous pouvez utiliser uniquement une version de débogage de votre script.

Max Shmelev
la source
6
belle explication cependant, le problème de l'OP était que certains scripts ( jquery.tmpl) n'ont pas, ne sont pas fournis, n'ont pas téléchargé la version non min du fichier. Le bundler ignore complètement les fichiers de script s'il n'a pas de version non min en mode débogage
Eonasdan
D'accord, belle explication mais elle ne répond pas du tout à la question d'OP.
Diego
2
La version courte ne fonctionnait pas pour moi. "script.js" serait inclus dans ces deux types de versions. J'ai basculé DEBUG / RELEASE et (quand j'ai regardé la source) 'script.js' était celui sélectionné / rendu.
user981375
4
user981375, vous devez également définir <compilation debug = "false" /> dans le fichier web.config
Max Shmelev
5
Je préfère cette réponse car il s'agit d'une approche de "meilleures pratiques" et explique comment les règles par défaut du bundler peuvent être suivies pour atteindre le même objectif.
James Reategui
5

Si tout ce que vous avez est une version réduite d'un fichier, la solution la plus simple que j'ai trouvée consiste à copier le fichier réduit, à supprimer .min du nom du fichier copié, puis à référencer le nom de fichier non réduit dans votre ensemble.

Par exemple, supposons que vous ayez acheté un composant js et qu'ils vous aient donné un fichier appelé some-lib-3.2.1.min.js. Pour utiliser ce fichier dans un ensemble, procédez comme suit:

  1. Copiez some-lib-3.2.1.min.js et renommez le fichier copié en some-lib-3.2.1.js. Incluez les deux fichiers dans votre projet.

  2. Référencez le fichier non minifié dans votre bundle, comme ceci:

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

Tout simplement parce que le fichier sans «min» dans le nom est en fait minifié ne devrait pas poser de problème (à part le fait qu'il est essentiellement illisible). Il n'est utilisé qu'en mode débogage et est écrit en tant que script séparé. Lorsqu'il n'est pas en mode débogage, le fichier min précompilé doit être inclus dans votre bundle.

joelfp
la source
4

J'ai trouvé une bonne solution qui fonctionne au moins dans MVC5, vous pouvez simplement utiliser à la Bundleplace de ScriptBundle. Il n'a pas le comportement intelligent ScriptBundleque nous n'aimons pas (ignorer .min, etc.) dans ce cas. Dans ma solution, j'utilise Bundlepour les scripts de partie 3D avec des fichiers .min et .map et j'utilise ScriptBundlepour notre code. Je n'ai remarqué aucun inconvénient à le faire. Pour le faire fonctionner de cette façon, vous devrez ajouter le fichier d'origine, par exemple angular.js, et il chargera angular.js dans le débogage et il regroupera les angular.min.js en mode de libération.

Ilya Chernomordik
la source
Cela ne semble pas fonctionner lorsque les optimisations sont désactivées ( ScriptTable.EnableOptimizations = false). Les chemins de script qui contiennent un modèle ne sont pas rendus (par exemple ~/Scripts/thirdpartylib/*.js). Il fait le travail quand EnableOptimizations = true, mais il en va ScriptBundle.
Steven Liekens
Je l'utilise également avec false (pendant le développement) et je n'ai pas de problèmes que vous décrivez, donc cela peut être quelque chose d'autre qui l'affecte pour vous.Vous devez également faire IncludeDirectory au lieu d'inclure pour que le modèle fonctionne.
Ilya Chernomordik
Êtes-vous sûr qu'il restitue la version ".min.js" de votre fichier? Utilisez-vous des bundles de l'espace de noms System.Web.Optimizationsou du package nuget Microsoft.Web.Optimizations?
Steven Liekens
J'utilise System.Web.Optimization et j'ai vérifié qu'il restitue la version min, mais j'ai compris que je n'utilisais pas IncludeDirectory en fait, mais il serait étrange que cela ne fonctionne pas avec la version min cependant ... Comme IncludeDirectory n'est pas assez pour moi, je fais un scan personnalisé et j'ajoute tout le filtre en utilisant Include, donc il se peut que le motif et IncludeDirectory ne fonctionnent pas correctement là-bas, bien que ce soit un peu étrange.
Ilya Chernomordik
1
Non, le problème est double: seul un .min.jsfichier existe et le *.jsmodèle ne correspond pas aux fichiers se terminant par .min.js.
Steven Liekens
3

Pour rendre les *.min.jsfichiers, vous devez désactiver BundleTable.EnableOptimizations, qui est un paramètre global qui s'applique à tous les bundles.

Si vous souhaitez activer les optimisations pour des ensembles spécifiques uniquement, vous pouvez créer votre propre ScriptBundletype qui active temporairement les optimisations lors de l'énumération des fichiers dans l'ensemble.

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

Utilisez OptimizedScriptBundleau lieu de ScriptBundlepour les bundles dont le fichier minifié doit toujours être utilisé, qu'il existe ou non un fichier non minifié.

Exemple pour l'interface utilisateur de Kendo pour ASP.NET MVC, qui est distribué comme une collection de fichiers uniquement minifiés.

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
la source
Je suis tombé sur des scripts manquants dans une action de publication de production, et pensant que c'était un problème MVC, j'ai trouvé cette réponse. Et voilà, le kendo est impliqué. Ayant travaillé dessus trop longtemps, je fais tout pour m'éloigner du kendo
Felipe
@Felipe J'étais dans la même situation, c'est pourquoi j'ai écrit cette réponse. Le kendo est horrible. J'espère que mon exemple est utile.
Steven Liekens
2

Pour mon cas, j'utilisais la (merveilleuse!) Bibliothèque Knockout.js qui est disponible en versions Debug / Non:

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

Pour que cela fonctionne, j'ai inclus "Knockout- {Version} .js" (sans débogage) dans mon bundle et j'ai obtenu le .debug. Fichier js en mode débogage.

AcidPAT
la source
1

Une façon simple de renommer le fichier .min, par exemple, vous avez abc.min.css, que de renommer ce fichier en abc_min.css et de l'ajouter à votre bundle. Je sais que ce n'est pas la bonne façon de le faire, mais juste une solution temporaire. merci et bon codage.

RK Sharma
la source
1
Chaque fois que nuget télécharge le fichier, vous devez le renommer ensuite.
Anirudha Gupta
Je sais que ce n'est pas la bonne façon de le faire, mais juste une solution temporaire
RK Sharma
1
mettre cette ligne fonctionne pour moi // BundleTable.EnableOptimizations = true;
Anirudha Gupta
0

Bundler a beaucoup d'avantages consultez cette page MAIS :

La plate-forme Microsoft MVC4 considère que vous avez au moins la version réduite et la version non réduite pour chaque ensemble de scripts ou de styles (d'autres fichiers comme Debug et vsdoc sont également disponibles). Nous avons donc des problèmes dans les situations où il n'y a qu'un seul de ces fichiers.

Vous pouvez modifier l'état de débogage dans le fichier web.config de façon permanente pour gérer la sortie:

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

Voir les changements de sortie! Le filtrage des fichiers a été modifié. Pour atteindre l'objectif, nous devons changer ignorer la filtration de cas qui changera la logique d'application!

Amirhossein Mehrvarzi
la source
1
L'ajout de debug = "false" ne fonctionne toujours pas pour moi. les fichiers min.js ne sont toujours pas inclus même si j'efface également la IgnoreList ...
MoSs
-21

Mes amis, je le garderais simplement jusqu'à ce que Microsoft agisse ensemble

Essaye ça

Dans RegisterBundles, créez ce bundle pour 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"
 ));

Dans _Layout.cshtml, mettez ceci:

@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")   
 }

De cette façon, nous obtenons le meilleur des bundles en production et une référence dans le débogage

Réparez-le lorsque Microsoft corrige son code MVC 4

user1819794
la source
3
Je ne suis pas du tout fan de cette solution proposée. Vous devez maintenant conserver l'ensemble des scripts dans (au moins) deux endroits
Fatal
Cela va à peu près à l'encontre de l'objectif du regroupement, vous ne pensez pas?
Oliver
4
Le regroupement fonctionne déjà de cette façon. Si vous exécutez le projet en mode débogage, chaque fichier CSS est chargé individuellement, mais lorsque vous l'exécutez en version, ils sont combinés et minifiés en un seul. Le code dans le bloc if est identique à ce qui est rendu sur la page automatiquement en mode débogage.
Chad Levy