Як я можу вказати явний порядок включення ScriptBundle?


91

Я випробовую функцію MVC4 System.Web.Optimization 1.0 ScriptBundle .

У мене така конфігурація:

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. Як я можу переконатись, що він дотримується порядку, в якому я додаю, включення виразів до набору?

Оновлення

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

З debug = false у web.config, комбінований сценарій спочатку має сценарій dosegs.js, але оскільки його визначення функції (конструктор об'єктів), яке викликається пізніше, він працює без помилок. Можливо, мініфікатор досить розумний, щоб з’ясувати залежності?

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

Тож зменшена версія не в тому порядку, який я очікую, але вона працює.

Відповіді:


18

Я не бачу такої поведінки на бітах RTM, чи використовуєте ви Microsoft ASP.NET Web Optimization Framework 1.0.0 біти: 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 для набору вміст dosegs.js був після модернізації ...


Я перейшов на версію 1.0. Дивіться моє оновлене запитання. Вміст dosegs.js включений спочатку до мініфікованої версії, але він працює, оскільки його функція викликається пізніше.
— jrummell

115

Ви можете написати власний замовник набору пакетів ( 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")

10
Це має спрацювати, але це також повинно бути непотрібним, оскільки замовник за замовчуванням, як правило, поважає порядок включень (він переносить лише кілька спеціальних файлів у верхню частину, тобто jquery, reset.css / normalize.css тощо). Це не повинно просувати вершини dose.js.
— Хао Кунг

1
@flipdoubt подає тут проблему з репрограмою
— Hao Kung

1
Це чудово працює, дякую! Але я погоджуюсь, це не повинно бути необхідним.
— CBarr

2
Це працює для мене. Вона сприяє jqueryui над бутстрапа , коли в відповідно до stackoverflow.com/questions/17367736 / ... мені потрібно перевернути.
— Сеткран,

1
@Hao Kung чи можемо ми замовити файли в каталозі include ?
— shaijut

52

Дякую, Дарін. Я додав метод розширення.

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

9
Досить гладка! : D Прямо зараз мені довелося змінити FileInfoдля BundleFileпідпису методу Interface. Вони його змінили.
— Леніель Маккаферрі,

так, вони змінили його у попередній версії, яка використовує фреймворк
— Owin

маленький Off-Topic: хтось має більше інформації про цей BundleFileклас? Для того, щоб об'єднати вбудовані ресурси, я намагаюся створити це, і для цього потрібен параметр (конкретний дочірній елемент) VirtualFileу своєму конструкторі.
— superjos

У мене таке саме запитання, мені потрібен екземпляр BundleFile, але не знаю як
— Rui

2
@superjos Я знаю, що це досить давно, але я відповім, якщо хтось ще має проблему. Це частина System.Web.Optimization.
— Талон

47

Оновлено відповідь, надану SoftLion, для обробки змін у MVC 5 (BundleFile проти 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());

Мені подобається використовувати вільний синтаксис, але він також працює з одним викликом методу, і всі скрипти передаються як параметри.


2
Працює в MVC 5. Подяка
— Паскаль Кармоні

4
Відмінно. Це має включити MS imho
— Анджело

працює як привабливість у веб-формах теж ... в основному це повинно добре працювати для всіх останніх версій!
— Сонячна Шарма

Дуже чисте і просте рішення. Дуже дякую.
— bunjeeb

5

Ви повинні мати змогу встановити замовлення за допомогою 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);

1

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

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


1

Відповідь @ Даріна Димитрова для мене ідеально працює, але мій проект написаний на 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)

Я постійно отримую цю помилку: Є Class 'AsIsBundleOrderer' must implement 'Function OrderFiles(context as ....)' for interface 'System.Web.Optimization.IBundleOrderer'ідеї?
— Mark Pieszak - Trilon.io
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.