not*_*ary 3 javascript asp.net bundling-and-minification
约束:我没有使用MVC,而是在我的Web应用程序中使用了常规的.aspx文件。也不使用母版页-每个页面都是不同的野兽,因此该解决方案不适合我。
我为捆绑和缩小而阅读的大多数示例都需要一些特殊的MVC标记,或者要求您先识别捆绑的脚本/样式表,然后再引用这些捆绑。我想避免每次在.aspx页中添加或修改.js引用时都重新编译DLL。
我对阅读Msft文档有些困惑。是否有一种方法(如ASP.NET控件)可以包装一系列script标签(或linkCSS的标签)来动态创建和使用包?我不想重新发明轮子,而是认真考虑创建自己的用户控件/自定义控件来处理这个问题。还有其他选择吗?
例如,寻找这样的东西:
<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>
Run Code Online (Sandbox Code Playgroud)
启用捆绑后,将自动用类似于以下内容的asp:AdHocScriptBundle单个script标签替换的内容:
<script type="text/javascript" src="/webappname/bundles/mypage_bundle.js?v=dh120398dh1298dh192d8hd32d"></script>
Run Code Online (Sandbox Code Playgroud)
并且当捆绑功能被禁用时,通常按以下方式输出内容:
<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>
Run Code Online (Sandbox Code Playgroud)
有什么想法吗?
无论如何即将推出自己的游戏,但如果已经有解决方案,请分享,谢谢!
我推出了自己的解决方案,效果很好!我创建了4个可用作自定义服务器控件的类:
这些调用函数围绕我的自定义绑定库提供,该库本身就是System.Web.Optimization API的包装。
在渲染ScriptBundle和StyleBundle然后我检查内部设置(同一个,我用它来设定EnableOptimizations,告诉页面要么使用捆绑的System.Web.Optimization API中),或者干脆写出来的正常script/ link标签。如果启用了捆绑功能,它将从我的自定义捆绑库中调用此函数(对于脚本,以下代码中样式的相似代码Bundler是我的自定义捆绑库的类,以防万一Microsoft更改了System.Web.Optimization API,层之间,这样我就不必更改代码了):
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);
}
Run Code Online (Sandbox Code Playgroud)
为了确保仅在尚不存在的捆绑包中创建它,我首先使用此方法检查捆绑包(在使用上述方法之前):
public static bool BundleExists(string virtualTargetPath)
{
return System.Web.Optimization.BundleTable.Bundles.GetBundleFor(virtualTargetPath) != null;
}
Run Code Online (Sandbox Code Playgroud)
然后,我使用此函数通过使用System.Web.Optimization将URL吐出到分发包:
public static System.Web.IHtmlString GetScriptBundleHTML(string virtualTargetPath)
{
return System.Web.Optimization.Scripts.Render(virtualTargetPath);
}
Run Code Online (Sandbox Code Playgroud)
在我的.aspx文件中,我这样做:
<%@ Register TagPrefix="cc1" Namespace="AdHocBundler" Assembly="AdHocBundler" %>
Run Code Online (Sandbox Code Playgroud)
...
<cc1:ScriptBundle name="MyBundle" runat="Server">
<cc1:script src='~/js/script1.js'/>
<cc1:script src='~/js/utils/script2.js'/>
</cc1:ScriptBundle>
Run Code Online (Sandbox Code Playgroud)
对我来说,诀窍在于,我必须转换script和link标记才能在ScriptBundleand StyleBundle控件中作为列表项使用,但之后效果很好,并且让我使用tilde运算符轻松引用相对于应用程序根目录(使用Page.ResolveClientUrl(),对创建模块内容很有帮助)。
感谢您对此SO答案的帮助,以帮助我弄清楚如何创建自定义集合控件:如何使用集合属性构建ASP.NET自定义控件?
更新:为了完全公开,我获得了共享ScriptBundle的代码的许可(StyleBundle几乎相同,因此未包括在内):
[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; }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2656 次 |
| 最近记录: |