web-dev-qa-db-fra.com

Comment puis-je spécifier une commande d'inclusion ScriptBundle explicite?

J'essaie la fonctionnalité MVC4 System.Web.Optimization 1.0 ScriptBundle .

J'ai la configuration suivante:

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        // shared scripts
        Bundle canvasScripts =
            new ScriptBundle(BundlePaths.CanvasScripts)
                .Include("~/Scripts/modernizr-*")
                .Include("~/Scripts/json2.js")
                .Include("~/Scripts/columnizer.js")
                .Include("~/Scripts/jquery.ui.message.min.js")
                .Include("~/Scripts/Shared/achievements.js")
                .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(canvasScripts);
    }
}

et la vue suivante:

<script type="text/javascript" src="@Scripts.Url(BundlePaths.CanvasScripts)"></script>

BundlePaths.CanvasScripts est "~/bundles/scripts/canvas". Cela rend ceci:

<script type="text/javascript" src="/bundles/scripts/canvas?v=UTH3XqH0UXWjJzi-gtX03eU183BJNpFNg8anioG14_41"></script>

Jusqu'ici tout va bien, sauf que ~/Scripts/Shared/achievements.js Est le premier script de la source fournie. Cela dépend de chaque script inclus avant lui dans ScriptBundle. Comment puis-je m'assurer qu'il respecte l'ordre dans lequel j'ajoute des instructions include au paquet?

Mettre à jour

Il s'agissait d'une application ASP.NET MVC 4 relativement nouvelle, mais elle faisait référence au package de version préliminaire de la structure d'optimisation. Je l'ai supprimé et ajouté le package RTM de http://nuget.org/packages/Microsoft.AspNet.Web.Optimization) . Avec le RTM version avec debug = true dans web.config, @Scripts.Render("~/bundles/scripts/canvas") rend les balises de script individuelles dans le bon ordre.

Avec debug = false dans web.config, le script combiné a d'abord le script réalisations.js, mais puisqu'il s'agit d'une définition de fonction (constructeur d'objet) appelée ultérieurement, il s'exécute sans erreur. Peut-être que le minificateur est assez intelligent pour comprendre les dépendances?

J'ai aussi essayé l'implémentation de IBundleOrderer que Darin Dimitrov a suggéré avec RTM) avec les deux options de débogage et le même comportement.

La version abrégée ne correspond donc pas à l'ordre que je prévois, mais cela fonctionne.

91
jrummell

Je ne vois pas ce comportement sur les bits RTM, utilisez-vous les bits Microsoft ASP.NET Web Optimization Framework 1.0.0: http://nuget.org/packages /Microsoft.AspNet.Web.Optimization ?

J'ai utilisé une reproduction similaire à votre exemple, basée sur un nouveau site Web d'application Internet MVC4.

J'ai ajouté à BundleConfig.RegisterBundles:

        Bundle canvasScripts =
            new ScriptBundle("~/bundles/scripts/canvas")
                .Include("~/Scripts/modernizr-*")
                .Include("~/Scripts/Shared/achievements.js")
                .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(canvasScripts); 

Et puis dans la page d'index par défaut, j'ai ajouté:

<script src="@Scripts.Url("~/bundles/scripts/canvas")"></script>

Et j’ai vérifié que, dans le javascript minifié du bundle, le contenu de réalisations.js était postérieur à la modernisation ...

18
Hao Kung

Vous pouvez écrire un bon de commande de bundles personnalisé ( IBundleOrderer ) pour vous assurer que les bundles sont inclus dans la commande que vous enregistrez:

public class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

et alors:

public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
        var bundle = new Bundle("~/bundles/scripts/canvas");
        bundle.Orderer = new AsIsBundleOrderer();
        bundle
            .Include("~/Scripts/modernizr-*")
            .Include("~/Scripts/json2.js")
            .Include("~/Scripts/columnizer.js")
            .Include("~/Scripts/jquery.ui.message.min.js")
            .Include("~/Scripts/Shared/achievements.js")
            .Include("~/Scripts/Shared/canvas.js");
        bundles.Add(bundle);
    }
}

et à votre avis:

@Scripts.Render("~/bundles/scripts/canvas")
113
Darin Dimitrov

Merci Darin. J'ai ajouté une méthode d'extension.

internal class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
    {
        return files;
    }
}

internal static class BundleExtensions
{
    public static Bundle ForceOrdered(this Bundle sb)
    {
        sb.Orderer = new AsIsBundleOrderer();
        return sb;
    }
}

Usage

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js",
                    "~/Scripts/jquery-migrate-{version}.js",

                    "~/Scripts/jquery.validate.js",
                    "~/Scripts/jquery.validate.messages_fr.js",
                    "~/Scripts/moon.jquery.validation-{version}.js",

                    "~/Scripts/jquery-ui-{version}.js"
                    ).ForceOrdered());
51
Softlion

Mise à jour de la réponse fournie par SoftLion pour gérer les modifications dans MVC 5 (BundleFile vs FileInfo).

internal class AsIsBundleOrderer : IBundleOrderer
{
    public virtual IEnumerable<BundleFile> OrderFiles(BundleContext context, IEnumerable<BundleFile> files)
    {
        return files;
    }
}

internal static class BundleExtensions
{
    public static Bundle ForceOrdered(this Bundle sb)
    {
        sb.Orderer = new AsIsBundleOrderer();
        return sb;
    }
}

Usage:

    bundles.Add(new ScriptBundle("~/content/js/site")
        .Include("~/content/scripts/jquery-{version}.js")
        .Include("~/content/scripts/bootstrap-{version}.js")
        .Include("~/content/scripts/jquery.validate-{version}")
        .ForceOrdered());

J'aime utiliser une syntaxe fluide, mais cela fonctionne également avec un seul appel de méthode et tous les scripts passés en paramètres.

47
Gerald Davis

Vous devriez pouvoir définir la commande à l'aide de BundleCollection.FileSetOrderList. Jetez un coup d'œil à ce billet de blog: http://weblogs.asp.net/imranbaloch/archive/2012/09/30/hidden-options-of-asp-net-bundling-and-minification.aspx . Le code dans votre instance serait quelque chose comme:

BundleFileSetOrdering bundleFileSetOrdering = new BundleFileSetOrdering("js");
bundleFileSetOrdering.Files.Add("~/Scripts/modernizr-*");
bundleFileSetOrdering.Files.Add("~/Scripts/json2.js");
bundleFileSetOrdering.Files.Add("~/Scripts/columnizer.js");
bundleFileSetOrdering.Files.Add("~/Scripts/jquery.ui.message.min.js");
bundleFileSetOrdering.Files.Add("~/Scripts/Shared/achievements.js");
bundleFileSetOrdering.Files.Add("~/Scripts/Shared/canvas.js");
bundles.FileSetOrderList.Add(bundleFileSetOrdering);
5
Arne H. Bitubekk

Vous devriez envisager d'utiliser Cassette http://getcassette.net/ Il prend en charge la détection automatique des dépendances de script en fonction des références de script trouvées dans chaque fichier.

Si vous préférez vous en tenir à la solution d'optimisation MS Web mais que vous aimez l'idée d'organiser des scripts basés sur des références de script, vous devriez lire mon billet de blog à l'adresse http://blogs.Microsoft.co.il/oric/2013/12/27)./building-single-page-application-bundle-orderer /

1
Ori Calvo

La réponse de @Darin Dimitrov fonctionne parfaitement pour moi, mais mon projet est écrit en VB, alors voici sa réponse convertie en VB

Public Class AsIsBundleOrderer
    Implements IBundleOrderer

    Public Function IBundleOrderer_OrderFiles(ByVal context As BundleContext, ByVal files As IEnumerable(Of FileInfo)) As IEnumerable(Of FileInfo) Implements IBundleOrderer.OrderFiles
        Return files
    End Function
End Class

Pour l'utiliser:

Dim scriptBundleMain = New ScriptBundle("~/Scripts/myBundle")
scriptBundleMain.Orderer = New AsIsBundleOrderer()
scriptBundleMain.Include(
    "~/Scripts/file1.js",
    "~/Scripts/file2.js"
)
bundles.Add(scriptBundleMain)
1
CBarr