如何使用ASP.NET捆绑和缩小无需重新编译? [英] How do I use ASP.NET bundling and minification without recompiling?

查看:105
本文介绍了如何使用ASP.NET捆绑和缩小无需重新编译?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

约束:我不使用MVC,只是普通的醇'的.aspx在我的web应用程序文件。不使用母版页或者 - 每个页面都是一个不同的野兽,这样的解决方案是不适合我。

Constraints: I'm not using MVC, just regular ol' .aspx files in my web app. Not using master pages either - each page is a different beast, so that solution isn't right for me.

我读过捆绑和微小大多数例子既需要一些特殊的标记MVC或要求您识别捆绑脚本/样式表在前面,然后参考这些软件包。我想避免每次我加一次重新编译DLL或修改在.aspx页面中一个.js引用。

Most examples I've read for bundling and minification require either some special MVC markup or require you to identify the bundled scripts / stylesheets up front and then refer to these bundles. I want to avoid recompiling DLLs every time I add or modify a .js reference in a .aspx page.

我有点自读MSFT文档..难倒有一个方法(如ASP.NET控件),我可以只是包装了一系列剧本标签(或链接为CSS标签)动态地创建和使用捆绑?我并不想另起炉灶,而是认真考虑建立处理这个我自己的用户控件/自定义控件。是否还有其他选择?

I'm a bit stumped from reading the Msft docs.. is there a way (like an ASP.NET control) that I can just wrap a series of script tags (or link tags for CSS) to create and use a bundle dynamically? I don't want to reinvent the wheel, but seriously considering creating my own user control / custom control that handles this. Are there other options?

例如,寻找这样的事情:

For example, looking for something like this:

<asp:AdHocScriptBundle id="mypage_bundle" runat="server">
    <script type="text/javascript" src="~/scripts/mypage1.js"></script>
    <script type="text/javascript" src="~/scripts/mypage2.js"></script>
    <script type="text/javascript" src="~/scripts/mypage3.js"></script>
</asp:AdHocScriptBundle>

这,捆绑被启用时,会自动替换 ASP的内容:有一个剧本标记AdHocScriptBundle 的类似这样的:

that, when bundling is enabled, automatically replaces the contents of asp:AdHocScriptBundle with a single script tag that resembles this:

<script type="text/javascript" src="/webappname/bundles/mypage_bundle.js?v=dh120398dh1298dh192d8hd32d"></script>

和捆绑时,禁用,正常输出的内容是这样的:

And when Bundling is disabled, outputs the contents normally like this:

<script type="text/javascript" src="/webappname/scripts/mypage1.js"></script>
<script type="text/javascript" src="/webappname/scripts/mypage2.js"></script>
<script type="text/javascript" src="/webappname/scripts/mypage3.js"></script>

有什么想法?

大概要推出自己的,但如果已经有此请您分享的解决方案,谢谢!

About to roll my own anyway, but if there is already a solution for this please share, thanks!

推荐答案

我推出我自己的解决方案,它的伟大工程!我创建了4个班,我可以作为自定义服务器控件使用:

I rolled my own solution and it works great! I created 4 classes that I can use as custom server controls:


  • ScriptBundle

  • 脚本

  • StyleBundle

  • 链接

在我定制的捆绑库这些通话功能这本身就是对System.Web.Optimization API的包装。

These call functions around my custom bundling library which is itself a wrapper for the System.Web.Optimization API.

在渲染的 ScriptBundle StyleBundle 然后我检查的内部设置(即我用设置的同一个它告诉页面要么使用捆绑,或者干脆写出来的正常剧本 EnableOptimizations 的System.Web.Optimization API中) C> / 链接标记。如果捆绑启用它从我的自定义捆绑库调用这个函数(脚本,类似code的样式寿捆扎机下code是类我的自定义捆绑库 - 以防万一微软改变了System.Web.Optimization API我想要一个层之间,这样我就不必尽可能多的改变我的code):

During Render of ScriptBundle and StyleBundle I then check an internal setting (the same one that I use to set EnableOptimizations in the System.Web.Optimization API) that tells the page to either use bundling, or simply write out the normal script / link tags. If Bundling is enabled it calls this function from my custom bundling library (for Scripts, similar code for Styles tho. Bundler in code below is the class for my custom bundling library - just in case Microsoft changes the System.Web.Optimization API I wanted a layer in-between so that I wouldn't have to change my code as much):

    public static void AddScriptBundle(string virtualTargetPath, params string[] virtualSourcePaths)
    {
        var scriptBundle = new System.Web.Optimization.ScriptBundle(virtualTargetPath);
        scriptBundle.Include(virtualSourcePaths);
        System.Web.Optimization.BundleTable.Bundles.Add(scriptBundle);
    }

要确保我只创建包,如果它不存在,我第一次用这个方法(用上面的方法之前)检查软件包:

To make sure that I only create the Bundle if it does not already exist, I first check for the Bundle using this method (before using the above method):

    public static bool BundleExists(string virtualTargetPath)
    {
        return System.Web.Optimization.BundleTable.Bundles.GetBundleFor(virtualTargetPath) != null;
    }

然后我用这个功能通过使用System.Web.Optimization吐出的URL包:

Then I use this function to spit out the URL to the bundle by using System.Web.Optimization:

    public static System.Web.IHtmlString GetScriptBundleHTML(string virtualTargetPath)
    {
        return System.Web.Optimization.Scripts.Render(virtualTargetPath);
    }

在我的.aspx文件,我这样做:

Within my .aspx files, I do this:

<%@ Register TagPrefix="cc1" Namespace="AdHocBundler" Assembly="AdHocBundler" %>

...

<cc1:ScriptBundle name="MyBundle" runat="Server">
    <cc1:script src='~/js/script1.js'/>
    <cc1:script src='~/js/utils/script2.js'/>
</cc1:ScriptBundle>

我的诀窍是搞清楚,我不得不转换剧本链接标签是工作的列表中项目的 ScriptBundle StyleBundle 控制,但之后,它的伟大工程,它让我用波浪线运营,方便相对于应用程序根引用(使用 Page.ResolveClientUrl(),这是一个用于创建模块内容有用)。

The trick for me was figuring out that I had to convert script and link tags to be work as list items within the ScriptBundle and StyleBundle controls, but after that it works great AND it let me use the tilde operator for easy references relative to app root (using Page.ResolveClientUrl(), which is helpful for creating module content).

由于去这个SO回答帮助我弄清楚如何创建自定义集合控件:<一href=\"http://stackoverflow.com/questions/123616/how-do-you-build-an-asp-net-custom-control-with-a-collection-property/123867#123867\">How你构建ASP.NET自定义控件与集合属性?

Thanks go to this SO answer for helping me figure out how to create a custom collection control: How do you build an ASP.NET custom control with a collection property?

更新:在充分披露的利益,我得到了分担ScriptBundle的code(StyleBundle几乎是相同的,因此没有包括)权限:

UPDATE: In the interest of full disclosure, I got permission to share the code for ScriptBundle (StyleBundle is almost identical, so did not include it):

[DefaultProperty("Name")]
[ParseChildren(true, DefaultProperty = "Scripts")]
public class ScriptBundle : Control
{
    public ScriptBundle()
    {
        this.Enabled = true;
        this.Scripts = new List<Script>();
    }

    [PersistenceMode(PersistenceMode.Attribute)]
    public String Name { get; set; }

    [PersistenceMode(PersistenceMode.Attribute)]
    [DefaultValue(true)]
    public Boolean Enabled { get; set; }

    [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public List<Script> Scripts { get; set; }

    protected override void Render(HtmlTextWriter writer)
    {
        if (String.IsNullOrEmpty(this.Name))
        {
            // Name is used to generate the bundle; tell dev if he forgot it
            throw new Exception("ScriptBundle Name is not defined.");
        }

        writer.BeginRender();

        if (this.Enabled && Bundler.EnableOptimizations)
        {
            if (this.Scripts.Count > 0)
            {
                string bundleName = String.Format("~/bundles{0}/{1}.js",
                    HttpContext.Current.Request.FilePath,
                    this.Name).ToLower();

                // create a bundle if not exists
                if (!Bundler.BundleExists(bundleName))
                {
                    string[] scriptPaths = new string[this.Scripts.Count];
                    int len = scriptPaths.Length;
                    for (int i = 0; i < len; i++)
                    {
                        if (!string.IsNullOrEmpty(this.Scripts[i].Src))
                        {
                            // no need for resolve client URL here - bundler already does it for us, so paths like "~/scripts" will already be expanded
                            scriptPaths[i] = this.Scripts[i].Src;
                        }
                    }
                    Bundler.AddScriptBundle(bundleName, scriptPaths);
                }

                // spit out a reference to bundle
                writer.Write(Bundler.GetScriptBundleHTML(bundleName));
            }
        }
        else
        {
            // do not use bundling. generate normal script tags for each Script
            foreach (Script s in this.Scripts)
            {
                if (!string.IsNullOrEmpty(s.Src))
                {
                    // render <script type='<type>' src='<src'>/> ... and resolve URL to expand tilde, which lets us use paths relative to app root
                    // calling writer.Write() directly since it has less overhead than using RenderBeginTag(), etc., assumption is no special/weird chars in the cc1:script attrs
                    writer.Write(String.Format(Script.TAG_FORMAT_DEFAULT,
                        s.Type,
                        Page.ResolveClientUrl(s.Src)));
                }
            }
        }
        writer.EndRender();
    }
}

public class Script
{
    public const String ATTR_TYPE_DEFAULT = "text/javascript";
    public const String TAG_FORMAT_DEFAULT = "<script type=\"{0}\" src=\"{1}\"></script>";

    public Script()
    {
        this.Type = ATTR_TYPE_DEFAULT;
        this.Src = null;
    }

    public String Type { get; set; }
    public String Src { get; set; }
    public String Language { get; set; }
}

这篇关于如何使用ASP.NET捆绑和缩小无需重新编译?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆