使用捆绑与 ASP.NET MVC 放缩法
在这一节我们将创建 ASP.NET MVC 项目,审查捆绑和缩小。首先,创建一个新的 ASP.NET MVC 互联网项目,命名为MvcBM ,而无需更改任何默认设置。
打开App_StartBundleConfig.cs文件并检查的 RegisterBundles
方法,用于创建、 注册和配置包。下面的代码演示RegisterBundles
方法的部分。
publicstaticvoidRegisterBundles(BundleCollection bundles){ bundles.Add(newScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));// Code removed for clarity.}
上面的代码中创建名为~/bundles/jquery ,其中包括所有适当的新 JavaScript 束 (这是调试或模糊不清但不是。vsdoc) 在脚本文件夹中的文件相匹配的通配符字符串"~/Scripts/jquery-{版本}.js"。对于 ASP.NET MVC 4,这意味着调试配置中,文件jquery 1.7.1.js将被添加到包。在发布配置, jquery 1.7.1.min.js将被添加。捆绑框架如以下几个共同的约定:
- 如果“FileX.min.js”和“FileX.js”都存在,请为发行版选择“.min”文件。
- 选择用于调试的非".min"版本。
- 忽略"-vsdoc"仅使用智能感知的文件 (如 jquery-1.7.1-vsdoc.js)。
如上所示的{version}
通配符匹配用于自动创建一个 jQuery 束具有适当版本的 jQuery脚本文件夹中。在此示例中,使用通配符提供了以下好处:
- 允许您使用 NuGet 更新到新的 jQuery 版本而无需更改前面的绑定代码或 jQuery 引用在您查看网页。
- 自动选择完整版,为调试配置和发布的".min"版本生成。
使用 CDN
以下代码将使用 CDN jQuery 绑定来替换本地 jQuery 绑定。
publicstaticvoidRegisterBundles(BundleCollection bundles){//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(// "~/Scripts/jquery-{version}.js")); bundles.UseCdn=true;//enable CDN support//add link to jquery on the CDNvar jqueryCdnPath ="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"; bundles.Add(newScriptBundle("~/bundles/jquery", jqueryCdnPath).Include("~/Scripts/jquery-{version}.js"));// Code removed for clarity.}
在上面的代码中,jQuery 将请求从 CDN 虽然在释放模式和 jQuery 的调试版本将被回迁本地在调试模式下。当使用 CDN,你应该有一个回退机制在 CDN 请求失败的情况下。下面的标记片段从布局文件的末尾显示脚本添加请求 jQuery 应 CDN 失败。
</footer> @Scripts.Render("~/bundles/jquery") <scripttype="text/javascript">if(typeof jQuery =='undefined'){var e = document.createElement('script'); e.src ='@Url.Content("~/Scripts/jquery-1.7.1.js")'; e.type ='text/javascript'; document.getElementsByTagName("head")[0].appendChild(e);}</script> @RenderSection("scripts", required: false) </body></html>
创建包
包类Include
方法需要的字符串数组,其中每个字符串是资源的虚拟路径。下面的代码从App_StartBundleConfig.cs文件的 RegisterBundles 方法显示出多个文件添加到包:
bundles.Add(newStyleBundle("~/Content/themes/base/css").Include("~/Content/themes/base/jquery.ui.core.css","~/Content/themes/base/jquery.ui.resizable.css","~/Content/themes/base/jquery.ui.selectable.css","~/Content/themes/base/jquery.ui.accordion.css","~/Content/themes/base/jquery.ui.autocomplete.css","~/Content/themes/base/jquery.ui.button.css","~/Content/themes/base/jquery.ui.dialog.css","~/Content/themes/base/jquery.ui.slider.css","~/Content/themes/base/jquery.ui.tabs.css","~/Content/themes/base/jquery.ui.datepicker.css","~/Content/themes/base/jquery.ui.progressbar.css","~/Content/themes/base/jquery.ui.theme.css"));
捆绑类IncludeDirectory
方法被提供要添加一个目录 (和 (可选) 的所有子目录) 中与搜索模式匹配的所有文件。包类IncludeDirectory
API 如下所示:
publicBundleIncludeDirectory(string directoryVirtualPath,// The Virtual Path for the directory.string searchPattern)// The search pattern.publicBundleIncludeDirectory(string directoryVirtualPath,// The Virtual Path for the directory.string searchPattern,// The search pattern.bool searchSubdirectories)// true to search subdirectories.
在视图中使用 Render 方法中,(对 CSS Styles.Render
) 和Scripts.Render
的 JavaScript 来引用的捆绑包。从ViewsShared\_Layout.cshtml文件下面的标记显示默认 ASP.NET 互联网项目视图如何引用 CSS 和 JavaScript 的捆绑包。
<!DOCTYPE html><htmllang="en"><head> @* Markup removed for clarity.*@ @Styles.Render("~/Content/themes/base/css", "~/Content/css") @Scripts.Render("~/bundles/modernizr")</head><body> @* Markup removed for clarity.*@ @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body></html>
请注意渲染方法采用字符串数组,因此您可以在一行代码中添加多个软件包。你一般会想要使用所创建的必要的 HTML 来引用该资产的渲染方法。您可以使用 Url
方法生成的 URL,该资产,而引用该资产所需的标记。假设你想要使用新的 HTML5 async属性。下面的代码演示如何引用 modernizr 使用Url
的方法。
<head> @*Markup removed for clarity*@ <metacharset="utf-8"/><title>@ViewBag.Title - MVC 4 B/M</title><linkhref="~/favicon.ico"rel="shortcut icon"type="image/x-icon"/><metaname="viewport"content="width=device-width"/> @Styles.Render("~/Content/css") @* @Scripts.Render("~/bundles/modernizr")*@ <scriptsrc='@Scripts.Url("~/bundles/modernizr")'async></script></head>
使用"*"通配符字符,请选择文件
Include
方法和IncludeDirectory
方法中的搜索模式中指定的虚拟路径可以接受一个"*"通配符字符作为前缀或后缀来中最后一个路径段。搜索字符串是区分大小写。IncludeDirectory
方法有选择搜索子目录。
与下面的 JavaScript 文件考虑一个项目:
- ScriptsCommonAddAltToImg.js
- ScriptsCommonToggleDiv.js
- ScriptsCommonToggleImg.js
- ScriptsCommonSub1ToggleLinks.js
下表显示的文件添加到捆绑使用通配符,如图所示:
电话 | 添加文件或引发异常 |
Include("~/Scripts/Common/*.js") | AddAltToImg.js,ToggleDiv.js,ToggleImg.js |
Include("~/Scripts/Common/T*.js") | 无效的模式的异常。通配符字符只允许对的前缀或后缀。 |
Include("~/Scripts/Common/*og.*") | 无效的模式的异常。只有一个通配符字符被允许。 |
"Include("~/Scripts/Common/T*") | ToggleDiv.js ToggleImg.js |
"Include("~/Scripts/Common/*") | 无效的模式的异常。一个纯通配符段不是有效的。 |
IncludeDirectory ("~/Scripts/Common","T *") | ToggleDiv.js ToggleImg.js |
IncludeDirectory("~/Scripts/Common", "T*",true) | ToggleDiv.js,ToggleImg.js,ToggleLinks.js |
显式地将每个文件添加到一捆是一般首选在通配符加载的文件,原因如下:
- 将脚本由通配符默认值添加到加载它们按字母顺序,通常不是你想。经常需要 (非字母) 按照特定的顺序添加 CSS 和 JavaScript 文件。通过添加一个自定义的IBundleOrderer实现,但显式添加每个文件都少出错,可以降低这种风险。例如,您可能会添加新的资产到文件夹在将来可能会要求您修改您的IBundleOrderer实现。
- 查看特定文件添加到使用通配符加载目录可以包含在引用该捆绑包的所有视图。如果查看特定脚本添加到包中,你可能会引用捆绑其他视图上一个 JavaScript 错误。
- 将其他文件导入的 CSS 文件导致两次加载导入的文件。例如,下面的代码创建一个束与大多数的 jQuery UI 的主题 CSS 文件加载两次。
bundles.Add(newStyleBundle("~/jQueryUI/themes/baseAll").IncludeDirectory("~/Content/themes/base","*.css"));
在每个 CSS 文件夹中的文件,包括Content hemesasejquery.ui.all.css文件带来的通配符"*.css"选择器。Jquery.ui.all.css文件中导入其他 CSS 文件。
原文:
Using Bundling and Minification with ASP.NET MVC
In this section we will create an ASP.NET MVC project to examine bundling and minification. First, create a new ASP.NET MVC internet project namedMvcBM without changing any of the defaults.
Open the App_StartBundleConfig.cs file and examine the RegisterBundles
method which is used to create, register and configure bundles. The following code shows a portion of the RegisterBundles
method.
publicstaticvoidRegisterBundles(BundleCollection bundles){ bundles.Add(newScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));// Code removed for clarity.}
The preceding code creates a new JavaScript bundle named ~/bundles/jquery that includes all the appropriate (that is debug or minified but not .vsdoc) files in the Scripts folder that match the wild card string "~/Scripts/jquery-{version}.js". For ASP.NET MVC 4, this means with a debug configuration, the file jquery-1.7.1.js will be added to the bundle. In a release configuration, jquery-1.7.1.min.js will be added. The bundling framework follows several common conventions such as:
- Selecting “.min” file for release when “FileX.min.js” and “FileX.js” exist.
- Selecting the non “.min” version for debug.
- Ignoring “-vsdoc” files (such as jquery-1.7.1-vsdoc.js), which are used only by IntelliSense.
The {version}
wild card matching shown above is used to automatically create a jQuery bundle with the appropriate version of jQuery in your Scriptsfolder. In this example, using a wild card provides the following benefits:
- Allows you to use NuGet to update to a newer jQuery version without changing the preceding bundling code or jQuery references in your view pages.
- Automatically selects the full version for debug configurations and the ".min" version for release builds.
Using a CDN
The follow code replaces the local jQuery bundle with a CDN jQuery bundle.
publicstaticvoidRegisterBundles(BundleCollection bundles){//bundles.Add(new ScriptBundle("~/bundles/jquery").Include(// "~/Scripts/jquery-{version}.js")); bundles.UseCdn=true;//enable CDN support//add link to jquery on the CDNvar jqueryCdnPath ="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"; bundles.Add(newScriptBundle("~/bundles/jquery", jqueryCdnPath).Include("~/Scripts/jquery-{version}.js"));// Code removed for clarity.}
In the code above, jQuery will be requested from the CDN while in release mode and the debug version of jQuery will be fetched locally in debug mode. When using a CDN, you should have a fallback mechanism in case the CDN request fails. The following markup fragment from the end of the layout file shows script added to request jQuery should the CDN fail.
</footer> @Scripts.Render("~/bundles/jquery") <scripttype="text/javascript">if(typeof jQuery =='undefined'){var e = document.createElement('script'); e.src ='@Url.Content("~/Scripts/jquery-1.7.1.js")'; e.type ='text/javascript'; document.getElementsByTagName("head")[0].appendChild(e);}</script> @RenderSection("scripts", required: false) </body></html>
Creating a Bundle
The Bundle class Include
method takes an array of strings, where each string is a virtual path to resource. The following code from the RegisterBundles method in the App_StartBundleConfig.cs file shows how multiple files are added to a bundle:
bundles.Add(newStyleBundle("~/Content/themes/base/css").Include("~/Content/themes/base/jquery.ui.core.css","~/Content/themes/base/jquery.ui.resizable.css","~/Content/themes/base/jquery.ui.selectable.css","~/Content/themes/base/jquery.ui.accordion.css","~/Content/themes/base/jquery.ui.autocomplete.css","~/Content/themes/base/jquery.ui.button.css","~/Content/themes/base/jquery.ui.dialog.css","~/Content/themes/base/jquery.ui.slider.css","~/Content/themes/base/jquery.ui.tabs.css","~/Content/themes/base/jquery.ui.datepicker.css","~/Content/themes/base/jquery.ui.progressbar.css","~/Content/themes/base/jquery.ui.theme.css"));
The Bundle class IncludeDirectory
method is provided to add all the files in a directory (and optionally all subdirectories) which match a search pattern. The Bundle class IncludeDirectory
API is shown below:
publicBundleIncludeDirectory(string directoryVirtualPath,// The Virtual Path for the directory.string searchPattern)// The search pattern.publicBundleIncludeDirectory(string directoryVirtualPath,// The Virtual Path for the directory.string searchPattern,// The search pattern.bool searchSubdirectories)// true to search subdirectories.
Bundles are referenced in views using the Render method , ( Styles.Render
for CSS and Scripts.Render
for JavaScript). The following markup from the ViewsShared\_Layout.cshtml file shows how the default ASP.NET internet project views reference CSS and JavaScript bundles.
<!DOCTYPE html><htmllang="en"><head> @* Markup removed for clarity.*@ @Styles.Render("~/Content/themes/base/css", "~/Content/css") @Scripts.Render("~/bundles/modernizr")</head><body> @* Markup removed for clarity.*@ @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body></html>
Notice the Render methods takes an array of strings, so you can add multiple bundles in one line of code. You will generally want to use the Render methods which create the necessary HTML to reference the asset. You can use the Url
method to generate the URL to the asset without the markup needed to reference the asset. Suppose you wanted to use the new HTML5 async attribute. The following code shows how to reference modernizr using the Url
method.
<head> @*Markup removed for clarity*@ <metacharset="utf-8"/><title>@ViewBag.Title - MVC 4 B/M</title><linkhref="~/favicon.ico"rel="shortcut icon"type="image/x-icon"/><metaname="viewport"content="width=device-width"/> @Styles.Render("~/Content/css") @* @Scripts.Render("~/bundles/modernizr")*@ <scriptsrc='@Scripts.Url("~/bundles/modernizr")'async></script></head>
Using the "*" Wildcard Character to Select Files
The virtual path specified in the Include
method and the search pattern in the IncludeDirectory
method can accept one "*" wildcard character as a prefix or suffix to in the last path segment. The search string is case insensitive. The IncludeDirectory
method has the option of searching subdirectories.
Consider a project with the following JavaScript files:
- ScriptsCommonAddAltToImg.js
- ScriptsCommonToggleDiv.js
- ScriptsCommonToggleImg.js
- ScriptsCommonSub1ToggleLinks.js
The following table shows the files added to a bundle using the wildcard as shown:
Call | Files Added or Exception Raised |
Include("~/Scripts/Common/*.js") | AddAltToImg.js, ToggleDiv.js, ToggleImg.js |
Include("~/Scripts/Common/T*.js") | Invalid pattern exception. The wildcard character is only allowed on the prefix or suffix. |
Include("~/Scripts/Common/*og.*") | Invalid pattern exception. Only one wildcard character is allowed. |
"Include("~/Scripts/Common/T*") | ToggleDiv.js, ToggleImg.js |
"Include("~/Scripts/Common/*") | Invalid pattern exception. A pure wildcard segment is not valid. |
IncludeDirectory("~/Scripts/Common", "T*") | ToggleDiv.js, ToggleImg.js |
IncludeDirectory("~/Scripts/Common", "T*",true) | ToggleDiv.js, ToggleImg.js, ToggleLinks.js |
Explicitly adding each file to a bundle is generally the preferred over wildcard loading of files for the following reasons:
- Adding scripts by wildcard defaults to loading them in alphabetical order, which is typically not what you want. CSS and JavaScript files frequently need to be added in a specific (non-alphabetic) order. You can mitigate this risk by adding a custom IBundleOrderer implementation, but explicitly adding each file is less error prone. For example, you might add new assets to a folder in the future which might require you to modify your IBundleOrderer implementation.
- View specific files added to a directory using wild card loading can be included in all views referencing that bundle. If the view specific script is added to a bundle, you may get a JavaScript error on other views that reference the bundle.
- CSS files that import other files result in the imported files loaded twice. For example, the following code creates a bundle with most of the jQuery UI theme CSS files loaded twice.
bundles.Add(newStyleBundle("~/jQueryUI/themes/baseAll").IncludeDirectory("~/Content/themes/base","*.css"));
The wild card selector "*.css" brings in each CSS file in the folder, including the Content hemesasejquery.ui.all.css file. The jquery.ui.all.cssfile imports other CSS files.