【问题标题】:ASP.NET MVC4 Bundle a single fileASP.NET MVC4 捆绑单个文件
【发布时间】:2012-10-09 16:16:20
【问题描述】:

有没有办法使用 MVC4 中的新捆绑功能来捆绑单个文件?我知道捆绑单个文件没有多大意义,但我想使用服务器端缩小并让 MVC 将哈希附加到 URL 的末尾以进行缓存。

我尝试了@Scripts.Url("~/Scripts/myscript.js"),但它似乎不起作用。

【问题讨论】:

    标签: asp.net asp.net-mvc-4 bundling-and-minification


    【解决方案1】:

    好吧,在你的包配置中定义一个只包含这个文件的包:

    bundles.Add(
        new ScriptBundle("~/bundles/myscript").Include("~/Scripts/myscript.js")
    );
    

    然后通过名称引用它在您的视图中使用它:

    @Scripts.Render("~/bundles/myscript")
    

    【讨论】:

    • 问题是我们的网站是非常动态的,因为我们有很多很多的白色标签,所以添加到 Global.asax 文件中的 BundleTable 不是一个选项 - 有没有办法即时完成?
    • 你说的on the fly是什么意思?请提供更多详细信息。如果您有许多脚本,您应该考虑将它们分组到文件夹中并按功能捆绑它们。
    • 看来我只能在应用程序启动时注册一个包。如果我在 Global.axax 文件之外尝试上面的代码,它就不起作用。我需要能够在申请期间的任何时间“注册”一个捆绑包,这样更有意义吗?
    • 何时/为什么需要在 Application_Start 之外注册捆绑包?
    • 因为我们的网站非常动态,我们有数百种不同的白色标签/皮肤,每个“皮肤”都有一堆每天都在变化的 Javascript 文件。设法将每个 CSS/JS 文件放入 AppStart 将是一场噩梦
    【解决方案2】:

    我需要这样的东西,这就是我想出的

    在视图上,我可以使用 HTML Helper 添加脚本或样式。这些都将接受 n 个参数。

    @Html.Style("~/Styles/someFile.css")
    @Html.Script("~/Scripts/foo.js", "~/Scripts/bar.js")
    

    所以我创建了一个扩展来为我处理这个问题。下面是这个类的样子。

    using System.Linq;
    using System.Web.Optimization;
    
    namespace System.Web.Mvc
    {
        public static class HtmlHelperExtensions
        {
    
            public static IHtmlString Script(this HtmlHelper helper, params string[] urls)
        {
            var bundleDirectory = "~/Scripts/bundles/" + MakeBundleName(".js", urls);
            var thisBundle = new ScriptBundle(bundleDirectory).Include(urls);
            BundleTable.Bundles.Add(thisBundle);
    
            return Scripts.Render(bundleDirectory);
        }
    
        public static IHtmlString Style(this HtmlHelper helper, params string[] urls)
        {
            var bundleDirectory = "~/Styles/bundles/" + MakeBundleName(".css", urls);
            var thisBundle = new StyleBundle(bundleDirectory).Include(urls);
            BundleTable.Bundles.Add(thisBundle);
    
            return Styles.Render(bundleDirectory);
        }
    
        private static string MakeBundleName(string type, params string[] urls)
        {
            var bundleSections = new List<string>();
    
            foreach (var item in urls)
            {
                bundleSections.Add(item.Replace("~/", "").Replace("/", ".").Replace(type, ""));
            }
    
            return string.Join("+", bundleSections.ToArray());
        }
        }
    }
    

    注意事项

    这会在捆绑“虚拟目录”存在的地方进行硬编码。因此,如果您的文件中有任何图像或其他任何内容的相对路径,它们就会中断。对于我们的用例,这对我们来说现在很好。

    捆绑包名称是自动生成的。同样,这对我们有用,但可能会更好。我可以看到一个简单的改进,您必须提供一个包路径和名称,其语法如下:@Html.Script("~/bundles/myBundleName","~/Scripts/foo.js", "~/Scripts/bar.js")


    我很高兴听到任何人可能对此进行的任何改进。

    【讨论】:

    • 谢谢我刚刚走上同一条路,很高兴有人走这条路
    • 你也应该添加using System.Collections.Generic;
    • 这段代码不是为每个页面视图创建一个新的捆绑包吗?或者 MVC 是否正确处理了 BundleTable 中的重复包(即,如果它具有相同的名称,那么旧的包会被删除吗?)。另外,它是否是多线程安全的(如果两个请求同时尝试访问 BundleTable.Bundles)
    • @youen 我不能 100% 确定你的所有问题,但我相信一旦创建了一个包,它就会被缓存。所以它应该在第一次访问时创建,然后缓存版本将在之后的任何时间访问。
    • @ChrisBarr 确实,浏览器会缓存文件,没有问题。但是在服务器端,每次调用BundleTable.Bundles.Add 时,都会在表中添加一个新条目(我已经用调试器检查过)。这可能不是什么大问题,但可能在数千个请求之后它会开始使用一些内存,并使 MVC 更难在列表中找到特定的包。解决方案只是在添加新包之前检查包不存在(同名)。
    【解决方案3】:

    我不知道,如果我说得对,但您可以随时添加捆绑包,只需将其添加到捆绑包集合中:

    BundleTable.Bundles.Add(new ScriptBundle("~/Scripts/myBundleName").Include(
                "~/Scripts/myscript.js"
                ));
    

    我不确定您打算如何在客户端包含捆绑包,但在捆绑包注册后,您可以使用以下代码获取缩小脚本文件的 url:

    string url = BundleTable.Bundles.ResolveBundleUrl("~/Scripts/myBundleName");
    

    在我的例子中,我只是通过 ajax 请求获取这个 url 并在客户端创建一个脚本标签。这样脚本文件将被缩小,并且 url 带有一个哈希码,因此浏览器应该缓存它,并且当包被更改时应该加载更新的版本。

    我希望这是你打算做的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-16
      • 2012-09-07
      • 1970-01-01
      • 1970-01-01
      • 2012-06-21
      • 2012-10-28
      • 2013-04-02
      • 2012-07-22
      相关资源
      最近更新 更多