我如何指定一个显式的ScriptBundle包含顺序?

我正在尝试MVC4 System.Web.Optimization 1.0 ScriptBundlefunction 。

我有以下configuration:

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

在web.config中debug = false的情况下,组合脚本首先具有这些plays.js脚本,但是由于它的函数定义(对象构造函数)稍后调用,所以它运行时没有错误。 也许这个缩小器足够聪明,能够发现依赖关系吗?

我也尝试了Darin Dimitrov用RTM和两个debugging选项build议的IBundleOrderer实现,它的performance也一样。

所以缩小版本是不是我所期望的顺序,但它的工作原理。

我没有看到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中,achievement.js的内容是在现代化之后…

您可以编写一个自定义绑定IBundleOrderer者( 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()); 

我喜欢使用stream利的语法,但它也适用于单个方法调用,并将所有脚本作为parameter passing。

您应该可以在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); 

您应该考虑使用Cassette http://getcassette.net/它支持基于每个文件内的脚本引用自动检测脚本依赖关系。;

如果你喜欢坚持MS Web Optimization解决scheme,但喜欢根据脚本引用来安排脚本的想法,你应该阅读我的博客文章http://blogs.microsoft.co.il/oric/2013/12/27/building-single -page应用束-订货者/

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