Як я можу вказати явний порядок включення 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.