Как я могу указать явный порядок включения ScriptBundle?


Я пробую система MVC4.Сеть.Оптимизация 1.0 ScriptBundle feature.

у меня есть следующие конфигурации:

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

и следующий вид:

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

здесь BundlePaths.CanvasScripts - это "~/bundles/scripts/canvas". Он делает это:

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

пока все хорошо, кроме ~/Scripts/Shared/achievements.js является первым скриптом в комплекте источника. Это зависит от каждого сценария включенными в ScriptBundle. как я могу гарантировать, что он соблюдает порядок, в котором я добавляю операторы include в пакет?

обновление

это было относительно новое ASP.NET приложение MVC 4, но оно ссылалось на пакет предварительной версии optimization framework. Я удалил его и добавил пакет RTM из http://nuget.org/packages/Microsoft.AspNet.Web.Optimization. с версией RTM с debug=true в web.config,@Scripts.Render("~/bundles/scripts/canvas") отображает отдельные теги скрипта в правильном порядке.

С debug=false в интернете.конфиг, комбинированный скрипт имеет свои достижения.сначала JS-скрипт, но поскольку его определение функции (конструктор объектов), которое вызывается позже, выполняется без ошибок. Возможно, минификатор достаточно умен, чтобы выяснить зависимости?

я тоже пробовал IBundleOrderer реализация, которую Дарин Димитров предложил с RTM с обоими вариантами отладки, и она вела себя одинаково.

таким образом, уменьшенная версия не в том порядке, который я ожидаю, но это работает.

7 88

7 ответов:

Я не вижу такого поведения на битах RTM, вы используете Microsoft ASP.NET Web Optimization Framework 1.0.0 bits:http://nuget.org/packages/Microsoft.AspNet.Web.Optimization?

я использовал аналогичное повторение для вашего образца, основанного на новом веб-сайте интернет-приложения MVC4.

я добавил в 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); 

и затем на странице индекса по умолчанию я добавил:

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

и я проверил, что в минимизированный javascript для пакета, содержание достижений.js был после модернизации...

вы могли бы написать пользовательский пакет заказчика (IBundleOrderer), что обеспечит пакеты включены в порядке их регистрации:

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

и затем:

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

а на ваш взгляд:

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

спасибо Дарин. Я добавил метод расширения.

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

использование

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());

обновлен ответ, предоставленный SoftLion для обработки изменений в 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;
    }
}

использование:

    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());

мне нравится использовать синтаксис fluent, но он также работает с одним вызовом метода и всеми скриптами, переданными в качестве параметров.

вы должны быть в состоянии установить порядок с помощью BundleCollection.FileSetOrderList. Посмотрите на это сообщение в блоге: http://weblogs.asp.net/imranbaloch/archive/2012/09/30/hidden-options-of-asp-net-bundling-and-minification.aspx . Код в вашем экземпляре будет что-то вроде:

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

вы должны рассмотреть возможность использования кассеты http://getcassette.net/ он поддерживает автоматическое определение зависимостей сценариев на основе ссылок на сценарии, найденных внутри каждого файла.

Если вы предпочитаете придерживаться решения MS Web Optimization, но, как и идея организации скриптов на основе ссылок на Скрипты, вы должны прочитать мой пост в блогеhttp://blogs.microsoft.co.il/oric/2013/12/27/building-single-page-application-bundle-orderer/

@ ответ Дарина Димитрова отлично работает для меня, но мой проект написан на VB, поэтому вот его ответ, преобразованный в 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

использовать:

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