【问题标题】:Make a script bundle include another script bundle使脚本包包含另一个脚本包
【发布时间】:2014-12-18 18:20:30
【问题描述】:

假设我配置了这两个脚本包:

bundles.Add(new ScriptBundle("~/Scripts/Bootstrap").Include(
        "~/Content/Scripts/jQuery/jquery-2.1.1.js",
        "~/Content/Scripts/Bootstrap/bootstrap.js"));

bundles.Add(new ScriptBundle("~/Scripts/jQuery").Include(
        "~/Content/Scripts/jQuery/jquery-2.1.1.js"));

如您所见,~/Scripts/Boostrap 使用一个 jQuery JavaScript 文件和一个 Bootstrap 文件。这是因为 Bootstrap 需要 jQuery 才能工作。

另一方面,~/Scripts/jQuery 仅由 jQuery 文件组成。

我想要两个包,以防视图只需要 jQuery 而不需要 Bootstrap。

但是,我在这里复制代码,我定义了 jQuery JavaScript 文件路径两次

有没有办法告诉~/Scripts/Boostrap 包使用或“注入”另一个包?

类似这样的:

bundles.Add(new ScriptBundle("~/Scripts/Bootstrap").UseBundle("~/Scripts/jQuery").Include(
        "~/Content/Scripts/Bootstrap/bootstrap.js"));

【问题讨论】:

  • 为什么不只是让 jQuery 包只有 jQuery,而引导程序包只有引导程序。在您看来,包括 jQuery,如有必要,请引入引导程序包。除了在 HTML 中保存一个脚本标签之外,我看不出在两个单独的包中包含 jquery 会真正为您带来什么。
  • @Tommy 我可以做到这一点,并且客户再做一个请求的工作几乎不会被注意到,但是如果有一种更优化的方法来完成我想要的,并且仍然让客户只发送一个两个脚本的单个请求,这会很棒
  • 不幸的是,这里没有什么可以说的,除了,不,这是不可能的。无法在另一个包中引用一个包。
  • 从程序员的角度来看,I want to have two bundles in case a view only needs jQuery and not Bootstrap 在我们对缓存一无所知的世界里听起来完全合乎逻辑。一旦涉及缓存,在第一次请求之后,每个视图捆绑的想法实际上比每个视图多个脚本的性能更差(通常情况下)。跨度>

标签: c# asp.net asp.net-mvc asp.net-mvc-3 asp.net-mvc-4


【解决方案1】:

让一个脚本包包含另一个脚本包

不直接使用捆绑类。

假设在您的场景中,企业决定为每个请求仅向客户端发送一个捆绑包。您已决定捆绑每个控制器所需的所有脚本(在这个神奇的世界中)。您可能会从以下内容开始:

bundles.Add(new ScriptBundle("~/Scripts/Home")
                .Include("~/Content/Scripts/jQuery/jquery-2.1.1.js",
                         "~/Content/Scripts/Bootstrap/bootstrap.js"
                         "~/Content/Scripts/Home.js"));

bundles.Add(new ScriptBundle("~/Scripts/Account")
                .Include("~/Content/Scripts/jQuery/jquery-2.1.1.js",
                         "~/Content/Scripts/Bootstrap/bootstrap.js"
                         "~/Content/Scripts/Account.js"));

然后意识到.Include(string[]) 只需要一个字符串数组,您可以将DRY 您的代码转换为:

var commonScripts = new List<string>()
{
    "~/Content/Scripts/jQuery/jquery-2.1.1.js",
    "~/Content/Scripts/Bootstrap/bootstrap.js"
};

var homeScripts = new List<string>()
{
  "~/Content/Scripts/Home.js"
};

bundles.Add(new ScriptBundle("~/bundles/home/")
                .Include(commonScripts.Concat(homeScripts).ToArray()));

var accountScripts = new List<string>()
{
  "~/Content/Scripts/Account.js"
};

bundles.Add(new ScriptBundle("~/bundles/account/")
                .Include(commonScripts.Concat(accountScripts).ToArray()));

我不推荐此解决方案背后的商业原因,但我认为解决它的逻辑可以类似地用于解决您的问题。

如果你认为你可能会有重复,你也可以:

                .Include(commonScripts.Concat(accountScripts)
                                      .Distinct()
                                      .ToArray()));

我个人不会在捆绑包中包含 jQuery 或 BootStrap,因为它们可以从许多在线 CDN 免费获得; A 表示我使用的带宽较少,B 客户端可能已经下载了我需要的脚本(CDN 仍然存在用于常见脚本/样式的原因)。

【讨论】:

    【解决方案2】:

    您还可以考虑创建一个 ComposableBundle 包装器类,它允许您使用 .UseBundle(someBundle) 语法组合包。

    例如以下类和扩展方法:

    public class ComposableBundle<T> where T : Bundle
    {
        private T _bundle;
        private List<string> _virtualPaths = new List<string>();
    
        public ComposableBundle(T bundle)
        {
            _bundle = bundle;
        }
    
        public string[] VirtualPaths
        {
            get { return _virtualPaths.ToArray(); }
        }
    
        public T Bundle
        {
            get { return _bundle; }
        }
    
        public ComposableBundle<T> Include(params string[] virtualPaths)
        {
            _virtualPaths.AddRange(virtualPaths);
            _bundle.Include(virtualPaths);
            return this;
        }
    
        public ComposableBundle<T> UseBundle(ComposableBundle<T> bundle)
        {
            _bundle.Include(bundle.VirtualPaths.ToArray());
            return this;
        }
    }
    
    public static class BundleExtensions
    {
        public static ComposableBundle<T> AsComposable<T>(this T bundle) where T : Bundle
        {
            return new ComposableBundle<T>(bundle);
        }
    
        public static ComposableBundle<T> Add<T>(this BundleCollection bundles, ComposableBundle<T> bundle) where T: Bundle
        {
            bundles.Add(bundle.Bundle);
            return bundle;
        }
    }
    

    允许你像这样配置你的包:

    var jQueryBundle = bundles.Add(new ScriptBundle("~/bundles/jquery").AsComposable()
                                .Include("~/Scripts/jquery-{version}.js"));
    
    bundles.Add(new ScriptBundle("~/bundles/jqueryui").AsComposable()
                    .UseBundle(jQueryBundle)
                    .Include("~/Scripts/jquery-ui-{version}.js"));
    

    【讨论】:

    • 包装很好,现在我也想使用this post 订购捆绑文件,如何混合使用?
    • 我写这篇文章已经有一段时间了,但我认为你应该能够在你设置_bundle.orderer的地方添加另一个流畅的方法UseOrderer(orderer)。如果它不起作用,我建议尝试一下并提出一个新问题。
    • 感谢您的回复,我试过了,但我遇到了错误,here 是问题所在。
    • UseBundle 而不是IncludeBundle 背后的原因是什么?我想你可以链接UseBundle,这对我来说意味着你想继续使用现有的措辞(Include)。
    • 另外,这并不重要,ComposableBundle&lt;T&gt;.UseBundle() 在数组上调用 .ToArray()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 2019-07-26
    • 2015-03-01
    • 2012-08-06
    • 2012-02-26
    • 1970-01-01
    • 2018-08-07
    相关资源
    最近更新 更多