ASP.NET Core 中的捆綁和縮小靜態(tài)資產(chǎn)

最近在B站上看到楊旭老師的ASP.NET Core 3.x 入門視頻(完結(jié))的第三節(jié)的ASP.NET視頻教程,里面提到到ASP.NET Core 中的捆綁和縮小靜態(tài)資產(chǎn),可以在微軟官方文檔ASP.NET Core 中的捆綁和縮小靜態(tài)資產(chǎn),特此記錄一下,感興趣的可以直接查看官方文檔。

ASP.NET Core 中的捆綁和縮小靜態(tài)資產(chǎn)

2020/09/02
作者:Scott AddieDavid Pine
本文介紹應(yīng)用捆綁和縮小的好處,包括如何在 ASP.NET Core Web 應(yīng)用中使用這些功能。

什么是捆綁和縮小

捆綁和縮小是可以在 Web 應(yīng)用中應(yīng)用的兩個不同的性能優(yōu)化。 捆綁和縮小一起使用,可減少服務(wù)器的請求數(shù)并減小請求的靜態(tài)資產(chǎn)的大小,從而提高性能。
捆綁和縮小主要縮短第一個頁面請求加載時間。 請求網(wǎng)頁后,瀏覽器會緩存靜態(tài)資產(chǎn)(JavaScript、CSS 和圖像)。 因此,在請求相同資產(chǎn)的同一站點上請求相同的一個或多個頁面時,捆綁和縮小不會提高性能。 如果未在資產(chǎn)上正確設(shè)置 expires 標(biāo)頭,且未使用捆綁和縮小,則瀏覽器的新鮮度啟發(fā)會在幾天后將資產(chǎn)標(biāo)記為過期。 此外,瀏覽器還需要對每個資產(chǎn)進(jìn)行驗證請求。 在這種情況下,即使在第一個頁面請求后,捆綁和縮小仍能提高性能。

捆綁

捆綁將多個文件合并到單個文件中。 捆綁可減少呈現(xiàn) Web 資產(chǎn)(如網(wǎng)頁)所需的服務(wù)器請求數(shù)。 可以專門為 CSS、JavaScript 等創(chuàng)建任意數(shù)量的單個捆綁。文件越少,從瀏覽器到服務(wù)器或從提供應(yīng)用程序的服務(wù)的 HTTP 請求就越少。 這會提高第一頁加載性能。

縮小

縮小在不更改功能的情況下從代碼中刪除不必要的字符。 因此,請求的資產(chǎn)(如 CSS、圖像和 JavaScript 文件)的大小大幅減小。 縮小的常見副作用包括將變量名稱縮短為一個字符、刪除注釋和不必要的空格。
考慮以下 JavaScript 函數(shù):

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/, ''));
}

縮小將函數(shù)縮減為以下內(nèi)容:

AddAltToImg=function(t,a){var r=$(t,a);r.attr("alt",r.attr("id").replace(/ID/,""))};

除了刪除注釋和不必要的空格外,還進(jìn)行了以下參數(shù)和變量名稱重命名:

原始 重命名
imageTagAndImageID t
imageContext a
imageElement r

捆綁和縮小的影響

操作 使用捆綁/縮小 不使用捆綁/縮小 更改
文件請求 7 18 157%
傳輸?shù)?KB 156 264.68 70%
加載時間(毫秒) 885 2360 167%

對于 HTTP 請求標(biāo)頭,瀏覽器非常詳細(xì)。 捆綁時,已發(fā)送的總字節(jié)數(shù)指標(biāo)明顯減少。 加載時間顯示了顯著改進(jìn),但本示例在本地運行。 將捆綁和縮小與通過網(wǎng)絡(luò)傳輸?shù)馁Y產(chǎn)結(jié)合使用時,可實現(xiàn)更高的性能提升。

選擇捆綁和縮小策略

MVC 和 Razor Pages 項目模板提供了一種用于捆綁和縮小的解決方案,它們構(gòu)成 JSON 配置文件。 第三方工具(如 Grunt 任務(wù)運行程序)以更復(fù)雜的方式完成相同的任務(wù)。 開發(fā)工作流需要捆綁和縮小之外的其他處理(如 linting 和圖像優(yōu)化)時,第三方工具非常適用。 通過使用設(shè)計時捆綁和縮小,在應(yīng)用部署之前創(chuàng)建縮小文件。 在部署之前進(jìn)行捆綁和縮小具有減少服務(wù)器負(fù)載的優(yōu)點。 但是,必須認(rèn)識到,設(shè)計時捆綁和縮小會增加生成的復(fù)雜性,并且僅適用于靜態(tài)文件。

配置捆綁和縮小

備注

需要將 BuildBundlerMinifier NuGet 包添加到項目中使其正常工作。
在 ASP.NET Core 2.1 或更高版本中,將名為 bundleconfig.json 的新 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.json 文件定義每個捆綁的選項。 在前面的示例中,為自定義 JavaScript (wwwroot/js/site.js) 和樣式表 (wwwroot/css/site.css) 文件定義了單一捆綁配置 。

配置選項包括:

  • outputFileName:要輸出的捆綁文件的名稱。 可包含 bundleconfig.json 文件中的相對路徑。 (必需)
  • inputFiles:要捆綁在一起的文件數(shù)組。 這些是配置文件的相對路徑。 可以選擇使用空值,*這將導(dǎo)致輸出文件為空。 支持 glob 模式。 - minify:輸出類型的縮小選項。 可選,默認(rèn)值 - minify: { enabled: true }
  • sourceMap:指示是否為捆綁的文件生成源映射的標(biāo)記。 可選,默認(rèn)值 - false
  • sourceMapRootPath:用于存儲所生成的源映射文件的根路徑。

向工作流添加文件

假設(shè)添加了額外的 custom.css 文件,類似于以下內(nèi)容:

.about, [role=main], [role=complementary] {
    margin-top: 60px;
}

footer {
    margin-top: 10px;
}

若要縮小 custom.css 并將其與 site.css 捆綁到 site.min.css 文件中,請將相對路徑添加到 bundleconfig.json :

[
  {
    "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 文件,并排除縮小的文件模式。

生成應(yīng)用程序。 打開 site.min.css 并注意 custom.css 的內(nèi)容將追加到文件末尾 。

基于環(huán)境的捆綁和縮小

最佳做法是,應(yīng)在生產(chǎn)環(huán)境中使用應(yīng)用的捆綁文件和縮小文件。 在開發(fā)過程中,原始文件可簡化應(yīng)用的調(diào)試。
使用視圖中的環(huán)境標(biāo)記幫助程序指定要包含在頁面中的文件。 環(huán)境標(biāo)記幫助程序僅在特定環(huán)境中運行時呈現(xiàn)其內(nèi)容。
以下 environment 標(biāo)記將在 Development環(huán)境中運行時呈現(xiàn)未處理的 CSS 文件:

<environment include="Development">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</environment>

以下 environment標(biāo)記將在非 Development 環(huán)境中運行時呈現(xiàn)捆綁的和縮小的 CSS 文件。 例如,在 ProductionStaging 中運行將觸發(fā)這些樣式表的呈現(xiàn):

<environment exclude="Development">
    <link rel="stylesheet" 
          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.json

在某些情況下,應(yīng)用的捆綁和縮小工作流需要額外處理。 示例包括圖像優(yōu)化、緩存清除和 CDN 資產(chǎn)處理。 為了滿足這些要求,可以將捆綁和縮小工作流轉(zhuǎn)換為使用 Gulp。

手動轉(zhuǎn)換捆綁和縮小工作流以使用 Gulp

將 package.json 文件(包含以下 devDependencies)添加到項目根:
警告

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.js 文件復(fù)制到項目根:

'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 任務(wù)

若要在 Visual Studio 中生成項目之前觸發(fā) Gulp 縮小任務(wù):

  1. 安裝 BuildBundlerMinifier NuGet 包。
  2. 將以下 MSBuild 目標(biāo)添加到項目文件:
<Target Name="MyPreCompileTarget" BeforeTargets="Build">
  <Exec Command="gulp min" />
</Target>

在此示例中,MyPreCompileTarget 目標(biāo)內(nèi)定義的所有任務(wù)在預(yù)定義的 Build 目標(biāo)之前運行。 Visual Studio 的輸出窗口中顯示類似于以下內(nèi)容的輸出:

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 ==========

其他資源

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容