- Razor页面
- 通用
- 客户端开发
- 标记帮助程序
- 高级
ASP.NET Core 中的捆绑和缩小静态资产
作者: Scott Addie和David 松树
本文介绍了应用绑定和缩减,包括如何使用 ASP.NET Core web apps 使用这些功能的好处。
什么是绑定和缩减
绑定和缩减是可以在 web 应用中应用的两个不同的性能优化。 绑定和缩减一起使用,可减少服务器请求数并减小请求的静态资产的大小,从而提高性能。
绑定和缩减主要改善第一页请求加载时间。 请求网页后,浏览器会缓存静态资产(JavaScript、CSS 和图像)。 因此,当在同一站点上请求相同的资源时,绑定和缩减不会提高性能。 如果未在资产上正确设置 expires 标头,且未使用捆绑和缩减,则浏览器的新鲜度试探法会在几天后将资产过期。 此外,浏览器还需要对每个资产进行验证请求。 在这种情况下,绑定和缩减在第一次请求页面后仍能改善性能。
捆绑
捆绑将多个文件合并到单个文件中。 绑定可减少呈现 web 资产(如网页)所需的服务器请求数。 可以专门为 CSS、JavaScript 等创建任意数量的单独包。文件越少,从浏览器到服务器的 HTTP 请求或提供应用程序的服务就会减少。 这会提高第一页的加载性能。
缩减
缩减从代码中删除不必要的字符,而不更改功能。 因此,请求的资产(如 CSS、图像和 JavaScript 文件)的大小大幅减小。 缩减的常见副作用包括将变量名称缩短为一个字符、删除注释和不必要的空格。
请考虑以下 JavaScript 函数:
AddAltToImg = function (imageTagAndImageID, imageContext) { ///<signature> ///<summary> Adds an alt tab to the image // </summary> //<param name="imgElement" type="String">The image selector.</param> //<param name="ContextForImage" type="String">The image context.</param> ///</signature> var imageElement = $(imageTagAndImageID, imageContext); imageElement.attr('alt', imageElement.attr('id').replace(/ID/, '')); }
缩减将函数降到了以下内容:
AddAltToImg=function(t,a){var r=$(t,a);r.attr("alt",r.attr("id").replace(/ID/,""))};
除了删除注释和不必要的空格外,还会将以下参数和变量名称重命名为:
原始 | 重命名 |
---|---|
imageTagAndImageID |
t |
imageContext |
a |
imageElement |
r |
捆绑和缩减的影响
下表概述了单独加载资产与使用绑定和缩减之间的差异:
操作 | 带有 B/M 的 | 无 B/M | 更改 |
---|---|---|---|
文件请求 | 7 | 18 | 157% |
已传输 KB | 156 | 264.68 | 70% |
加载时间(毫秒) | 885 | 2360 | 167% |
对于 HTTP 请求标头,浏览器非常详细。 绑定的字节总数指标明显减少了绑定的时间。 加载时间显示了显著改进,但本示例在本地运行。 将捆绑与缩减与通过网络传输的资产结合使用时,可实现更高的性能提升。
选择捆绑和缩减策略
MVC 和 Razor Pages 项目模板提供了一种现成的解决方案,可用于缩减和 JSON 配置文件。 第三方工具(如Grunt任务运行程序)以更复杂的方式完成相同的任务。 当开发工作流需要处理超过绑定和缩减—如 linting 和图像优化)时,第三方工具非常合适。 通过使用设计时绑定和缩减,缩小文件是在应用部署之前创建的。 在部署之前绑定和缩小提供了降低服务器负载的优点。 但是,必须认识到,设计时绑定和缩减会增加生成的复杂性,并且仅适用于静态文件。
配置捆绑和缩减
在 ASP.NET Core 2.0 或更早版本中,MVC 和 Razor Pages 项目模板提供了一个bundleconfig配置文件,该文件定义每个绑定的选项:
在 ASP.NET Core 2.1 或更高版本中,将名为bundleconfig的新 JSON 文件添加到 MVC 或 Razor Pages 项目根。 在该文件中包含以下 JSON 作为起始点:
[ { "outputFileName": "wwwroot/css/site.min.css", "inputFiles": [ "wwwroot/css/site.css" ] }, { "outputFileName": "wwwroot/js/site.min.js", "inputFiles": [ "wwwroot/js/site.js" ], "minify": { "enabled": true, "renameLocals": true }, "sourceMap": false } ]
Bundleconfig文件定义每个绑定的选项。 在前面的示例中,为自定义 JavaScript (wwwroot/js/node.js)和样式表(wwwroot/css/站点导航)文件定义了单个捆绑配置。
配置选项包括:
outputFileName
:要输出的绑定文件的名称。 可以包含bundleconfig文件中的相对路径。 (必需)inputFiles
:要捆绑在一起的文件的数组。 这些是配置文件的相对路径。 可选,* 空值将导致空的输出文件。 支持通配模式。minify
:输出类型的缩减选项。 可选,默认值-minify: { enabled: true }
- 每个输出文件类型都有配置选项。
includeInProject
:指示是否将生成的文件添加到项目文件的标记。 可选,默认值为 falsesourceMap
:标记,指示是否为绑定的文件生成源映射。 可选,默认值为 falsesourceMapRootPath
:用于存储生成的源映射文件的根路径。
绑定和缩减的生成时执行
BuildBundlerMinifier NuGet 包允许在生成时执行绑定和缩减。 包注入在生成和清理时间运行的MSBuild 目标。 Bundleconfig文件由生成过程进行分析,以便基于定义的配置生成输出文件。
备注
BuildBundlerMinifier 属于 GitHub 上的社区驱动项目,Microsoft 不提供支持。 应在此处归档问题。
-
Visual Studio
将BuildBundlerMinifier包添加到项目。
生成此项目。 "输出" 窗口中将显示以下内容:
1>------ Build started: Project: BuildBundlerMinifierApp, Configuration: Debug Any CPU ------ 1> 1>Bundler: Begin processing bundleconfig.json 1> Minified wwwroot/css/site.min.css 1> Minified wwwroot/js/site.min.js 1>Bundler: Done processing bundleconfig.json 1>BuildBundlerMinifierApp -> C:\BuildBundlerMinifierApp\bin\Debug\netcoreapp2.0\BuildBundlerMinifierApp.dll ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
清理项目。 "输出" 窗口中将显示以下内容:
1>------ Clean started: Project: BuildBundlerMinifierApp, Configuration: Debug Any CPU ------ 1> 1>Bundler: Cleaning output from bundleconfig.json 1>Bundler: Done cleaning output file from bundleconfig.json ========== Clean: 1 succeeded, 0 failed, 0 skipped ==========
-
.NET Core CLI
将BuildBundlerMinifier包添加到项目:
dotnet add package BuildBundlerMinifier
如果使用 ASP.NET Core 1.x,还原新添加的包:
dotnet restore
生成项目:
dotnet build
将显示以下内容:
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Bundler: Begin processing bundleconfig.json Bundler: Done processing bundleconfig.json BuildBundlerMinifierApp -> C:\BuildBundlerMinifierApp\bin\Debug\netcoreapp2.0\BuildBundlerMinifierApp.dll
清理项目:
dotnet clean
将显示以下输出:
Microsoft (R) Build Engine version 15.4.8.50001 for .NET Core Copyright (C) Microsoft Corporation. All rights reserved. Bundler: Cleaning output from bundleconfig.json Bundler: Done cleaning output file from bundleconfig.json
绑定和缩减的即席执行
可以在不生成项目的情况下即席运行捆绑和缩减任务。 将BundlerMinifier NuGet 包添加到项目:
<DotNetCliToolReference Include="BundlerMinifier.Core" Version="2.6.362" />
备注
BundlerMinifier 属于 GitHub 上的社区驱动项目,Microsoft 不提供支持。 应在此处归档问题。
此包扩展以包括.NET Core CLI dotnet 捆绑工具。 可以在 "包管理器控制台" (PMC)窗口或命令行界面中执行以下命令:
dotnet bundle
重要
NuGet 包管理器将依赖项添加到 * .csproj 文件作为 <PackageReference />
节点。 dotnet bundle
命令注册.NET Core CLI 时,才<DotNetCliToolReference />
使用节点。 请相应地修改 * .csproj 文件。
向工作流添加文件
假设添加了其他自定义 .css文件的示例类似于以下内容:
.about, [role=main], [role=complementary] { margin-top: 60px; } footer { margin-top: 10px; }
若要缩小自定义 css并将其与站点 中的内容捆绑在一起,请将相对路径添加到bundleconfig:
[ { "outputFileName": "wwwroot/css/site.min.css", "inputFiles": [ "wwwroot/css/site.css", "wwwroot/css/custom.css" ] }, { "outputFileName": "wwwroot/js/site.min.js", "inputFiles": [ "wwwroot/js/site.js" ], "minify": { "enabled": true, "renameLocals": true }, "sourceMap": false } ]
备注
或者,可以使用以下组合模式:
"inputFiles": ["wwwroot/**/!(*.min).css" ]
此组合模式匹配所有 CSS 文件,并排除缩小文件模式。
生成应用程序。 打开 "网站"。最小 css ,请注意,自定义 css的内容将追加到文件末尾。
基于环境的捆绑和缩减
最佳做法是,应在生产环境中使用应用的捆绑文件和缩小文件。 在开发过程中,原始文件可简化应用程序的调试。
通过在视图中使用环境标记帮助器来指定要包含在页面中的文件。 环境标记帮助程序仅在特定环境中运行时呈现其内容。
以下 environment
标记将在 Development
环境中运行时呈现未处理的 CSS 文件:
<environment include="Development"> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment>
<environment names="Development"> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment>
当在非 Development
环境中运行时,以下 environment
标记将呈现捆绑的和缩小的 CSS 文件。 例如,在 Production
或 Staging
中运行将触发这些样式表的呈现:
<environment exclude="Development"> <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment>
<environment names="Staging,Production"> <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment>
从 Gulp 使用 bundleconfig
在某些情况下,应用的绑定和缩减工作流需要额外处理。 示例包括图像优化、缓存清除和 CDN 资产处理。 为了满足这些要求,你可以将绑定和缩减工作流转换为使用 Gulp。
使用捆绑程序 & 缩小器扩展
Visual Studio捆绑程序 & 缩小器扩展处理到 Gulp 的转换。
备注
捆绑程序 & 缩小器扩展属于 Microsoft 不提供支持的 GitHub 上的社区驱动项目。 应在此处归档问题。
右键单击解决方案资源管理器中的bundleconfig文件,然后选择捆绑程序 & 缩小器 > 转换为 Gulp ... :
将gulpfile和包文件添加到项目。 安装 package.json 文件的 devDependencies
部分中列出的支持的 npm 包。
在 PMC 窗口中运行以下命令,以将 Gulp CLI 作为全局依赖项安装:
npm i -g gulp-cli
Gulpfile文件读取输入、输出和设置的bundleconfig文件。
'use strict'; var gulp = require('gulp'), concat = require('gulp-concat'), cssmin = require('gulp-cssmin'), htmlmin = require('gulp-htmlmin'), uglify = require('gulp-uglify'), merge = require('merge-stream'), del = require('del'), bundleconfig = require('./bundleconfig.json'); // Code omitted for brevity
手动转换
如果 Visual Studio 和/或捆绑程序 & 缩小器扩展不可用,请手动转换。
使用以下 devDependencies
将包 json文件添加到项目根目录:
警告
gulp-uglify
模块不支持 ECMAScript (ES) 2015/ES6 和更高版本。 安装gulp-terser而不是 gulp-uglify
来使用 ES2015/ES6 或更高版本。
"devDependencies": { "del": "^3.0.0", "gulp": "^4.0.0", "gulp-concat": "^2.6.1", "gulp-cssmin": "^0.2.0", "gulp-htmlmin": "^3.0.0", "gulp-uglify": "^3.0.0", "merge-stream": "^1.0.1" }
通过在与 package 相同的级别上运行以下命令来安装依赖项 。 json:
npm i
安装 Gulp CLI 作为全局依赖项:
npm i -g gulp-cli
将下面的gulpfile文件复制到项目根:
'use strict'; var gulp = require('gulp'), concat = require('gulp-concat'), cssmin = require('gulp-cssmin'), htmlmin = require('gulp-htmlmin'), uglify = require('gulp-uglify'), merge = require('merge-stream'), del = require('del'), bundleconfig = require('./bundleconfig.json'); const regex = { css: /\.css$/, html: /\.(html|htm)$/, js: /\.js$/ }; gulp.task('min:js', async function () { merge(getBundles(regex.js).map(bundle => { return gulp.src(bundle.inputFiles, { base: '.' }) .pipe(concat(bundle.outputFileName)) .pipe(uglify()) .pipe(gulp.dest('.')); })) }); gulp.task('min:css', async function () { merge(getBundles(regex.css).map(bundle => { return gulp.src(bundle.inputFiles, { base: '.' }) .pipe(concat(bundle.outputFileName)) .pipe(cssmin()) .pipe(gulp.dest('.')); })) }); gulp.task('min:html', async function () { merge(getBundles(regex.html).map(bundle => { return gulp.src(bundle.inputFiles, { base: '.' }) .pipe(concat(bundle.outputFileName)) .pipe(htmlmin({ collapseWhitespace: true, minifyCSS: true, minifyJS: true })) .pipe(gulp.dest('.')); })) }); gulp.task('min', gulp.series(['min:js', 'min:css', 'min:html'])); gulp.task('clean', () => { return del(bundleconfig.map(bundle => bundle.outputFileName)); }); gulp.task('watch', () => { getBundles(regex.js).forEach( bundle => gulp.watch(bundle.inputFiles, gulp.series(["min:js"]))); getBundles(regex.css).forEach( bundle => gulp.watch(bundle.inputFiles, gulp.series(["min:css"]))); getBundles(regex.html).forEach( bundle => gulp.watch(bundle.inputFiles, gulp.series(['min:html']))); }); const getBundles = (regexPattern) => { return bundleconfig.filter(bundle => { return regexPattern.test(bundle.outputFileName); }); }; gulp.task('default', gulp.series("min"));
运行 Gulp 任务
若要在 Visual Studio 中生成项目之前触发 Gulp 缩减任务,请将以下MSBuild 目标添加到 * .csproj 文件:
<Target Name="MyPreCompileTarget" BeforeTargets="Build"> <Exec Command="gulp min" /> </Target>
在此示例中,MyPreCompileTarget
目标内定义的所有任务在预定义 Build
目标之前运行。 Visual Studio 的输出窗口中显示类似于以下内容的输出:
1>------ Build started: Project: BuildBundlerMinifierApp, Configuration: Debug Any CPU ------ 1>BuildBundlerMinifierApp -> C:\BuildBundlerMinifierApp\bin\Debug\netcoreapp2.0\BuildBundlerMinifierApp.dll 1>[14:17:49] Using gulpfile C:\BuildBundlerMinifierApp\gulpfile.js 1>[14:17:49] Starting 'min:js'... 1>[14:17:49] Starting 'min:css'... 1>[14:17:49] Starting 'min:html'... 1>[14:17:49] Finished 'min:js' after 83 ms 1>[14:17:49] Finished 'min:css' after 88 ms ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========