如何指定一个明确的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应用程序,但它引用了优化框架预发行包。我删除了它,并从http://nuget.org/packages/Microsoft.AspNet.Web.Optimization添加了RTM包。对于web.config中带有debug = true的RTM版本,@Scripts.Render("~/bundles/scripts/canvas")将以正确的顺序呈现各个脚本标签。

在web.config中使用debug = false时,合并的脚本首先具有Achievements.js脚本,但是由于它是稍后调用的函数定义(对象构造函数),因此运行时没有错误。缩小器也许足够聪明以找出依赖关系?

我还尝试了IBundleOrdererDarin Dimitrov建议的RTM在两个调试选项下的实现,并且其表现相同。

因此,缩小版本与我期望的顺序不符,但可以正常工作。

Answers:


18

我没有在RTM位上看到此行为,您是否正在使用Microsoft ASP.NET Web优化框架1.0.0位:http : //nuget.org/packages/Microsoft.AspNet.Web.Optimization

基于新的MVC4 Internet应用程序网站,我对您的样本使用了类似的repro。

我添加到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中,Achievements.js的内容是在更新之后...


我升级到1.0版本。看到我更新的问题。Achievement.js的内容首先包含在精简版中,但由于其后来的功能而起作用。
jrummell 2012年

114

您可以编写一个自定义的捆绑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
这应该可行,但也不必要,因为默认排序器通常会遵循include的顺序(它只会将一些特殊文件提升到顶部,例如jquery,reset.css / normalize.css等)。不应将Achievements.js提升到最高。
郝宫

1
@flipdoubt在此处向repro提出问题:aspnetoptimization.codeplex.com/workitem/list/advanced
郝公

1
这很完美,谢谢!我同意,但这不是必须的。
CBarr

2
这对我有用。根据stackoverflow.com/questions/17367736/,它正在通过引导程序来促进jqueryui 。我需要翻转它。
Sethcran 2014年

1
@Hao Kung我们可以订购包含目录中的文件吗?
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现在我不得不改变FileInfoBundleFile在接口方法的签名。他们改变了。
Leniel Maccaferri

是的,他们改变了它在使用的Owin框架的预发布版本
Softlion

一点小话题:有人在这BundleFile堂课上有更多的信息吗?为了捆绑嵌入式资源,我试图实例化它,并且它VirtualFile的构造函数中需要一个(具体的子对象)参数。
superjos 2013年

我有同样的问题,我需要实例化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中工作。谢谢
Pascal Carmoni 2014年

4
优秀的。MS imho应该将其包括在内
Angelo

在Web窗体中也一样起作用……基本上,它对于所有最新版本都应该工作正常!
Sunny Sharma

非常干净和简单的解决方案。非常感谢。
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

@Darin Dimitrov的答案对我来说非常有效,但是我的项目是用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 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.