¿Paquete / declaración dinámica declarativa para MVC?

¿Hay alguna acción o forma de conexión (como un paquete de NuGet) que me permita declarar?.js, .css, e idealmente.less archivos en las vistas y parciales de MVC donde los uso, ¿y los tengo automáticamente en tiempo de ejecución agrupados y reducidos en producción? (a.k.a. "Autobunding")

He probado el paquete MVC 4 incorporado. No me gusta que los paquetes se definan lejos de donde el autor de una página esperaría encontrarlos, enBundleConfig.cs . Esto no es viable para los miembros del equipo que no son de C #.

Comoun ejemplo de lo que estoy buscando, esto es lo que me improviso usandoSquishIt.

ExtendedViewPage.cs

/// <summary>
/// Caches a bundle of .js and/or .css specific to this ViewPage, at a path similar to:
/// shared_signinpartial_F3BD3CCE1DFCEA70F5524C57164EB48E.js
/// </summary>
public abstract class ExtendedViewPage<TModel> : WebViewPage<TModel> {
    // This is where I keep my assets, and since I don't actually store any in my root,
    // I emit all my bundles here. I also use the the web deployment engine,
    // and remove extra files on publish, so I never personally have to clean them up,
    // and I also don't have to hand-identify generated bundles from original code.
    // However, to keep from needing to give the app write permissions
    // on a static content folder, or collocate bundles with original assets,
    // or conform to a specific asset path, this should surely be configurable
    private const string ASSET_PATH = "~/assets/";

    /// <summary>
    /// Emits here the bundled resources declared with "AddResources" on all child controls
    /// </summary>
    public MvcHtmlString ResourceLinks {
        get {
            return MvcHtmlString.Create(
                string.Join("", CssResourceLinks) + string.Join("", JsResourceLinks));
        }
    }

    // This allows all resources to be specified in a single command,
    // which permits .css and .js resources to be declared in an
    // interwoven manner, in any order the site author prefers
    // For me, this makes it clearer, to group my related .css and .js links,
    // and to place my often control-specific CSS near last in the list
    /// <summary>
    /// Queues compressible resources to be emitted with the ResourceLinks directive
    /// </summary>
    /// <param name="resourceFiles">Project paths to JavaScript and/or CSS files</param>
    public void AddResources(params string[] resourceFiles) {
        var css = FilterFileExtension(resourceFiles, ".css");
        AddCssResources(css);
        var js = FilterFileExtension(resourceFiles, ".js");
        AddJsResources(js);
    }

    /// <summary>
    /// Bundles JavaScript files to be emitted with the ResourceLinks directive
    /// </summary>
    /// <param name="resourceFiles">Zero or more project paths to JavaScript files</param>
    public void AddJsResources(params string[] resourceFiles) {
        if (resourceFiles.Any()) {
            JavaScriptBundle jsBundle = Bundle.JavaScript();
            foreach (string jsFile in resourceFiles) {
                jsBundle.Add(jsFile);
            }
            // Pages render from the inside-out, which is required for us to expose
            // our resources declared in children to the parent where they are emitted
            // however, it also means our resources naturally collect here in an order
            // that is probably not what the site author intends.
            // We reverse the order with insert
            JsResourceLinks.Insert(0, jsBundle.MvcRender(ASSET_PATH + ViewIdentifier + "_#.js"));
        }
    }

    /// <summary>
    /// Bundles CSS files to be emitted with the ResourceLinks directive
    /// </summary>
    /// <param name="resourceFiles">Zero or more project paths to CSS files</param>
    public void AddCssResources(params string[] resourceFiles) {
        // Create a separate reference for each CSS path, since CSS files typically include path-relative images.
        foreach (
            var cssFolder in resourceFiles.
                GroupBy(r => r.Substring(0, r.LastIndexOf('/')).ToLowerInvariant()).
                // Note the CssResourceLinks.Insert command below reverses not only desirably
                // the order of view emission, but also undesirably reverses the order of resources within this one view.
                // for this page we'll 'pre-reverse' them. There's probably a clearer way to address this.
                Reverse()) {
            CSSBundle cssBundle = Bundle.Css();
            foreach (string cssFile in cssFolder) {
                cssBundle.Add(cssFile);
            }
            // See JsResourceLinks.Insert comment above
            CssResourceLinks.Insert(0, cssBundle.MvcRender(cssFolder.Key + "/" + ViewIdentifier + "_#.css"));
        }
    }

    #region private implementation
    private string _viewIdentifier = null;
    // ViewIdentifier returns a site-unique name for the current control, such as "shared_signinpartial"
    // Some security wonks may take issue with exposing folder structure here
    // It may be appropriate to obfuscate it with a checksum
    private string ViewIdentifier {
        get {
            if (_viewIdentifier == null) {
                _viewIdentifier =
                    // VirtualPath uniquely identifies the currently rendering View or Partial,
                    // such as "~/Views/Shared/SignInPartial.cshtml"
                    Path.GetFileNameWithoutExtension(VirtualPath).
                    // This "Substring" truncates the ~/Views/ or ~/Areas/ in my build, in others
                    // but it is probably inappropriate to make this assumption.
                    // It is certainly possible to have views in the root.
                    // Substring(8).
                    // It's assumed all of these bundles will be output to a single folder,
                    // to keep filesystem write-access minimal, so we flatten them here.
                    Replace("/", "_").
                    // The following assumes a typical MS filesystem, preserve-but-ignore case.
                    // The .NET string recommendations suggest instead using ToUpperInvariant
                    // for such an operation, but this was just a personal preference.
                    // My IIS rules typically drop the case on all content served.
                    // It may be altogether inappropriate to alter,
                    // although appending the MD5 hash ensure it does no harm on other platforms,
                    // while still collapsing the cases where multiply-cased aliases are used
                    ToLowerInvariant();
            }
            return _viewIdentifier;
        }
    }

    private List<MvcHtmlString> CssResourceLinks {
        get { return getContextHtmlStringList("SquishItCssResourceLinks"); }
    }

    private List<MvcHtmlString> JsResourceLinks {
        get { return getContextHtmlStringList("SquishItJsResourceLinks"); }
    }

    // Note that at the resource render, if no bundles of a specific type (.css or .js)
    // have been provided, this performs the unnecessary operation of instanciating a new List<MvcHtmlString>
    // and adding it to the HttpContext.Items. This get/set could benefit from some clarification.
    private List<MvcHtmlString> getContextHtmlStringList(string itemName) {
        IDictionary contextItems = Context.ApplicationInstance.Context.Items;
        List<MvcHtmlString> resourceLinks;
        if (contextItems.Contains(itemName)) {
            resourceLinks = contextItems[itemName] as List<MvcHtmlString>;
        }
        else {
            resourceLinks = new List<MvcHtmlString>();
            contextItems.Add(itemName, resourceLinks);
        }
        return resourceLinks;
    }

    private string[] FilterFileExtension(string[] filenames, string mustEndWith) {
        IEnumerable<string> filtered =
            filenames.Where(r => r.EndsWith(mustEndWith, StringComparison.OrdinalIgnoreCase));
        return filtered.ToArray();
    }
    #endregion private implementation
}

PageWithHeaderLayout.cshtml (ejemplo de uso)

@{
    AddResources(
        Links.Assets.Common.Script.GoogleAnalytics_js,
        Links.Assets.Common.Style.ProprietaryTheme.jquery_ui_1_8_23_custom_css,
        Links.Assets.Common.Style.SiteStandards_css,
        Links.Assets.Common.CdnMirror.jquery._1_7_2.jquery_js,
        Links.Assets.Common.CdnMirror.jQuery_Validate._2_0_0pre.jquery_validate_120826_js,
        Links.Assets.Common.CdnMirror.jqueryui._1_8_23.jquery_ui_min_js,
        Links.Assets.Common.JqueryPlugins.templates.jquery_tmpl_min_js,
        Links.Assets.Common.JqueryPlugins.jquery_ajaxmanager_js,
        Links.Assets.Common.JqueryPlugins.hashchange.jquery_ba_hashchange_min_js
        );
}

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>@ViewBag.Title</title>
    <meta name="description" content="@ViewBag.Description" />
    <meta name="keywords" content="@ViewBag.Keywords" />
    <link rel="shortcut icon" href="@Url.Content("~/favicon.ico")" type="image/x-icon" />
    <!-- all bundles from all page components are emitted here -->
    @ResourceLinks
</head>
<body>
    @Html.Partial(MVC.Common.Views.ContextNavigationTree)
    <div id="pageContent">
        @RenderBody()
    </div>
</body>
</html>

Lamentablemente lo escribí, así que tiene muchas limitaciones. Los scripts no se eliminan de la duplicación, hace falta un enfoque simple para la delineación de paquetes, recientemente agregué un truco feo para permitir.less apoyo, etc.

¿Hay alguna solución existente para hacer esto?

Respuestas a la pregunta(2)

Su respuesta a la pregunta