由于默認(rèn)的 ASP.NET MVC 模板使用了 Bundle 技術(shù),大家開始接受并喜歡上這種技術(shù)。Bundle 技術(shù)通過 Micorosoft.AspNet.Web.Optimization 包實現(xiàn),如果在 ASP.NET WebForm 項目中引入這個包及其依賴包,在 ASP.NET WebForm 項目中使用 Bundle 技術(shù)也非常容易。
創(chuàng)新互聯(lián)專注于鎮(zhèn)安企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站開發(fā),購物商城網(wǎng)站建設(shè)。鎮(zhèn)安網(wǎng)站建設(shè)公司,為鎮(zhèn)安等地區(qū)提供建站服務(wù)。全流程按需求定制網(wǎng)站,專業(yè)設(shè)計,全程項目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)
關(guān)于在 WebForm 中使用 Bundle 技術(shù)的簡短說明
通過 NuGet 很容易在 WebForm 項目中引入
Microsoft.AspNet.Web.Optimization
包及其依賴包。不過在 MVC 項目的 Razor 頁面中可以使用類似下面的語句引入資源@Scripts.Render("...")而在
*.aspx
頁面中則需要通過<%= %>
來引入了:<%@ Import Namespace="System.Web.Optimization" %> // ... <%= Scripts.Render("...") %>備注 有些資料中是使用的
<%: %>
,我實在沒有發(fā)現(xiàn)它和<%= %>
有啥區(qū)別,但至少我在《ASP.NET Reference》的《Code Render Blocks》一節(jié)找到了<%= %>
,卻暫時沒在官方文檔里找到<%: %>
然后,我在一個使用了 EasyUI 的項目中使用了 Bundle 技術(shù)。才開始一切正常,至到第一個 Release 版本測試的那一天,“血案”發(fā)生了——
由于一個腳本錯誤,EasyUI 沒有生效。最終原因是 Bunlde 在 Release 版中將 EasyUI 的腳本壓縮了——當(dāng)然,定位到這個原因還是經(jīng)歷了一翻周折,這就不細(xì)說了。
這個解決方案理論上只需要在配置里加一句話就行:
BundleTable.EnableOptimizations = false;
但問題在于,這樣一來,為了一個 EasyUI,就放棄了所有腳本的壓縮,而僅僅只是合并,效果折半,只能當(dāng)作萬不得已的備選。
先看看原本的 Bundle 配置(已簡化)
public static void Register(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/libs") .Include("~/scripts/jquery-{version}.js") .Include("~/scripts/jquery.eaysui-{versoin}.js") .Include("~/scripts/locale/easyui-lang-zh_CN.js") .IncludeDirectory("~/scripts/app", "*.js", true) ); }
這段配置先引入了 jquery,再引入了 easyui,最后引入了一些為當(dāng)前項目寫的公共腳本。為了實現(xiàn)解決方案二,必須要改成分三個 Bundle 引入,同時還得想辦法阻止壓縮其中一個 Bundle。
要分段,簡單
public static void Register(BundleCollection bundles) { bundles.Add(new ScriptBundle("~/jquery") .Include("~/scripts/jquery-{version}.js") ); bundles.Add(new ScriptBundle("~/easyui") .Include("~/scripts/jquery.eaysui-{versoin}.js") .Include("~/scripts/locale/easyui-lang-zh_CN.js") ); bundles.Add(new ScriptBundle("~/libs") .IncludeDirectory("~/scripts/app", "*.js", true) ); }
但為了阻止壓縮,查了文檔,也搜索了不少資料都沒找到解決辦法,所以只好看源碼分析了,請出 JetBrains dotPeek。分析代碼之后得出結(jié)論,只需要去掉默認(rèn)的 Transform 就行
// bundles.Add(new ScriptBundle("~/easyui") // .Include("~/scripts/jquery.eaysui-{versoin}.js") // .Include("~/scripts/locale/easyui-lang-zh_CN.js") // ); Bundle easyuiBundle = new ScriptBundle("~/easyui") .Include("~/scripts/jquery.eaysui-{versoin}.js") .Include("~/scripts/locale/easyui-lang-zh_CN.js") ); easyuiBundle.Transforms.Clear(); bundles.Add(easyuiBundle);
關(guān)鍵代碼的分析說明
首先從 ScriptBunlde 入手
public class ScriptBundle: Bundle { public ScriptBundle(string virtualPath) : this(virtualPath, (string) null) {} public ScriptBundle(string virtualPath, string cdnPath) : base(virtualPath, cdnPath, (IBundleTransform) new JsMinify() ) { this.ConcatenationToken = ";" + Environment.NewLine; } }可以看出,ScriptBunlde 的構(gòu)建最終是通過其基類 Bunlde 中帶 IBunldeTransform 參數(shù)的那一個來構(gòu)造的。再看 Bunlde 的關(guān)鍵代碼
public class Bunlde public IList<IBundleTransform> Transforms { get { return this._transforms; } } public Bundle( string virtualPath, string cdnPath, params IBundleTransform[] transforms ) { // ... foreach(IBundleTransform bundleTransform in transforms) { this._transforms.Add(bundleTransform); } } }容易理解,ScriptBunlde 構(gòu)建的時候往 Transforms 中添加了一默認(rèn)的 Transform——JsMinify,從名字就可以看出來,這是用來壓縮腳本的。而 IBundleTransform 只有一個接口方法
public interface IBundleTransform { void Process(BundleContext context, BundleResponse response); }看樣子它是在處理 BundleResponse。而 BundleResponse 中定義有文本類型的 Content 和 ContentType 屬性,以及一個 IEnumerable<BundleFile> Files。
為什么是 Files 而不是 File 呢,我猜 Content 中包含的是一個 Bundle 中所有文件的內(nèi)容,而不是某一個文件的內(nèi)容。要驗證也很容易,自己實現(xiàn)個 IBundleTransform 試下就行了
Bundle b = new ScriptBundle("~/test") .Include(...) .Include(...); b.Transforms.Clear();b.Transforms.Add(new MyTransform()) // MyTransform 可以自由發(fā)揮,我其實啥都沒寫,只是在 Process 里打了個斷點,檢查了 response 的屬性值而已實驗證明在 BundleResponse 傳入 Transforms 之前,其 Content 就已經(jīng)有所有引入文件的內(nèi)容了。
方案二解決了方案一不能解決的問題,但同時也帶來了新問題。原來只需要一句話就能引入所有腳本
@Scripts.Render("~/libs")
而現(xiàn)在需要 3 句話
@Scripts.Render("~/jquery") @Scripts.Render("~/easyui") @Scripts.Render("~/libs")
鑒于方案二帶來的新問題,試想,如果有一個東西,能把 3 個 Bundle 對象組合起來,變成一個 Bundle 對象,豈不是就解決了?
于是,我發(fā)明了 Bundle 的 Bundle,不妨就叫 BundleBundle 吧。
public class BundleBundle : Bundle{ readonly List<Bundle> bundles = new List<Bundle>(); public BundleBundle(string virtualPath) : base(virtualPath) { } public BundleBundle Include(Bundle bundle) { bundles.Add(bundle); return this; } // 在引入 Bundle 對象時申明清空 Transforms,這幾乎就是為 EasyUI 準(zhǔn)備的 public BundleBundle Include(Bundle bundle, bool isClearTransform) { if (isClearTransform) { bundle.Transforms.Clear(); } bundles.Add(bundle); return this; } public override BundleResponse GenerateBundleResponse(BundleContext context) { List<BundleFile> allFiles = new List<BundleFile>(); StringBuilder content = new StringBuilder(); string contentType = null; foreach (Bundle b in bundles) { var r = b.GenerateBundleResponse(context); content.Append(r.Content); // 考慮到 BundleBundle 可能用于 CSS,所以這里進(jìn)行一次判斷, // 只在 ScriptBundle 后面加分號(兼容 ASI 風(fēng)格腳本) // 這里可能會出現(xiàn)在已有分號的代碼后面加分號的情況, // 考慮到只會浪費 1 個字節(jié),忍了 if (b is ScriptBundle) { content.Append(';'); } content.AppendLine(); allFiles.AddRange(r.Files); if (contentType == null) { contentType = r.ContentType; } } var response = new BundleResponse(content.ToString(), allFiles); response.ContentType = contentType; return response; } }
使用 BundleBundle 也簡單,就像這樣
bundles.Add(new BundleBundle("~/libs") .Include(new ScriptBundle("~/bundle/jquery") .Include("~/scripts/jquery-{version}.js") ) .Include( new ScriptBundle("~/bundle/easyui") .Include("~/scripts/jquery.easyui-{version}.js") .Include("~/scripts/locale/easyui-lang-zh_CN.js") ) .Include(new ScriptBundle("~/bundle/app") .IncludeDirectory("~/scripts/app", "*.js", true) ) );
然后
@Scripts.Render("~/libs")
注意,每個子 Bundle 都有名字,但這些名字不能直接給 @Scripts.Render() 使用,因為它們并沒有直接加入 BundleTable.Bundles 中。但名字是必須的,而且不能是 null,不信就試試。
當(dāng)前名稱:Bundle小鎮(zhèn)中由EasyUI引發(fā)的“血案”
網(wǎng)址分享:http://www.rwnh.cn/article46/jjsjhg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、企業(yè)網(wǎng)站制作、自適應(yīng)網(wǎng)站、小程序開發(fā)、域名注冊、App設(shè)計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)