Bagikan melalui


Bundling dan Minification

oleh Rick Anderson

Bundling dan minifikasi adalah dua teknik yang dapat Anda gunakan di ASP.NET 4.5 untuk meningkatkan waktu muat permintaan. Bundling dan minifikasi meningkatkan waktu muat dengan mengurangi jumlah permintaan ke server dan mengurangi ukuran aset yang diminta (seperti CSS dan JavaScript.)

Sebagian besar browser utama saat ini membatasi jumlah koneksi simultan per setiap nama host menjadi enam. Itu berarti bahwa sementara enam permintaan sedang diproses, permintaan tambahan untuk aset pada host akan diantrekan oleh browser. Pada gambar di bawah ini, tab jaringan alat pengembang IE F12 menunjukkan waktu untuk aset yang diperlukan oleh tampilan Tentang aplikasi sampel.

B/M

Bilah abu-abu menunjukkan waktu permintaan diantrekan oleh browser yang menunggu enam batas koneksi. Bilah kuning adalah waktu permintaan untuk byte pertama, yaitu, waktu yang diperlukan untuk mengirim permintaan dan menerima respons pertama dari server. Bilah biru menunjukkan waktu yang diperlukan untuk menerima data respons dari server. Anda dapat mengeklik dua kali pada aset untuk mendapatkan informasi waktu terperinci. Misalnya, gambar berikut menunjukkan detail waktu untuk memuat file /Scripts/MyScripts/JavaScript6.js .

Cuplikan layar yang memperlihatkan tab jaringan alat pengembang A S P dot NET dengan URL permintaan aset di kolom kiri dan waktunya di kolom kanan.

Gambar sebelumnya menunjukkan peristiwa Mulai , yang memberikan waktu permintaan diantrekan karena browser membatasi jumlah koneksi simultan. Dalam hal ini, permintaan diantrekan selama 46 milidetik menunggu permintaan lain selesai.

Bundling

Bundling adalah fitur baru di ASP.NET 4.5 yang memudahkan untuk menggabungkan atau menggabungkan beberapa file ke dalam satu file. Anda dapat membuat CSS, JavaScript, dan bundel lainnya. Lebih sedikit file berarti lebih sedikit permintaan HTTP dan yang dapat meningkatkan performa pemuatan halaman pertama.

Gambar berikut menunjukkan tampilan waktu yang sama dari tampilan Tentang yang ditampilkan sebelumnya, tetapi kali ini dengan bundel dan minifikasi diaktifkan.

Cuplikan layar yang memperlihatkan tab detail waktu aset pada alat pengembang I E F 12. Acara Mulai disorot.

Minification

Minifikasi melakukan berbagai pengoptimalan kode yang berbeda untuk skrip atau css, seperti menghapus spasi putih dan komentar yang tidak perlu dan mempersingkat nama variabel menjadi satu karakter. Pertimbangkan fungsi JavaScript berikut.

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

Setelah minifikasi, fungsi dikurangi menjadi berikut:

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

Selain menghapus komentar dan spasi kosong yang tidak perlu, parameter dan nama variabel berikut diganti namanya (disingkat) sebagai berikut:

Original Renamed
imageTagAndImageID n
imageContext t
imageElement i

Dampak Bundling dan Minification

Tabel berikut ini memperlihatkan beberapa perbedaan penting antara mencantumkan semua aset satu per satu dan menggunakan bundling dan minifikasi (B/M) dalam program sampel.

Menggunakan B/M Tanpa B/M Ubah
Permintaan File 9 34 256%
KB Terkirim 3.26 11.92 266%
KB Diterima 388.51 530 36%
Waktu Muat 510 MS 780 MS 53%

Byte yang dikirim memiliki pengurangan yang signifikan dengan bundling karena browser cukup verbose dengan header HTTP yang mereka terapkan pada permintaan. Pengurangan byte yang diterima tidak sebesar karena file terbesar (Scripts\jquery-ui-1.8.11.min.js dan Scripts\jquery-1.7.1.min.js) sudah dikurangi. Catatan: Waktu pada program sampel menggunakan alat Fiddler untuk mensimulasikan jaringan yang lambat. (Dari menu Aturan Fiddler, pilih Performa lalu Simulasikan Kecepatan Modem.)

Debugging Bundled dan Minified JavaScript

Sangat mudah untuk men-debug JavaScript Anda di lingkungan pengembangan (di mana Elemen kompilasi dalam file Web.config diatur ke debug="true" ) karena file JavaScript tidak dibundel atau dikurangi. Anda juga dapat men-debug build rilis tempat file JavaScript Anda dibundel dan dikurangi. Dengan menggunakan alat pengembang IE F12, Anda men-debug fungsi JavaScript yang disertakan dalam bundel yang dikurangi menggunakan pendekatan berikut:

  1. Pilih tab Skrip lalu pilih tombol Mulai penelusuran kesalahan .
  2. Pilih bundel yang berisi fungsi JavaScript yang ingin Anda debug menggunakan tombol aset.
    Cuplikan layar yang memperlihatkan tab Skrip alat pengembang I E F 12. Kotak input Cari Skrip, bundel, dan fungsi Skrip Java disorot.
  3. Format JavaScript yang dikurangi dengan memilih tombol KonfigurasiGambar yang memperlihatkan ikon tombol Konfigurasi. , lalu pilih Format JavaScript.
  4. Dalam kotak input Cari Skrip , pilih nama fungsi yang ingin Anda debug. Dalam gambar berikut, AddAltToImg dimasukkan dalam kotak input Skrip Pencarian .
    Cuplikan layar yang memperlihatkan tab Skrip alat pengembang I E F 12. Kotak input Cari Skrip dengan Tambahkan Alt Ke lmg yang dimasukkan di dalamnya disorot.

Untuk informasi selengkapnya tentang penelusuran kesalahan dengan alat pengembang F12, lihat artikel MSDN Menggunakan Alat Pengembang F12 untuk Men-debug Kesalahan JavaScript.

Mengontrol Bundling dan Minifikasi

Bundling dan minifikasi diaktifkan atau dinonaktifkan dengan mengatur nilai atribut debug di Elemen kompilasi dalam file Web.config . Dalam XML berikut, debug diatur ke true sehingga bundling dan minifikasi dinonaktifkan.

<system.web>
    <compilation debug="true" />
    <!-- Lines removed for clarity. -->
</system.web>

Untuk mengaktifkan bundel dan minifikasi, atur nilai ke debug "false". Anda dapat mengambil alih pengaturan Web.config dengan EnableOptimizations properti di BundleTable kelas . Kode berikut memungkinkan bundel dan minifikasi dan mengambil alih pengaturan apa pun dalam file Web.config .

public static void RegisterBundles(BundleCollection bundles)
{
    bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                 "~/Scripts/jquery-{version}.js"));

    // Code removed for clarity.
    BundleTable.EnableOptimizations = true;
}

Catatan

Kecuali EnableOptimizations adalah true atau atribut debug dalam Elemen kompilasi dalam file Web.config diatur ke false, file tidak akan dibundel atau dikurangi. Selain itu, versi .min file tidak akan digunakan, versi debug lengkap akan dipilih. EnableOptimizationsmengambil alih atribut debug di Elemen kompilasi dalam file Web.config

Menggunakan Bundling dan Minification dengan ASP.NET Web Forms dan Web Pages

Menggunakan Bundling dan Minification dengan ASP.NET MVC

Di bagian ini kita akan membuat proyek MVC ASP.NET untuk memeriksa bundling dan minifikasi. Pertama, buat proyek internet ASP.NET MVC baru bernama MvcBM tanpa mengubah salah satu default.

Buka file App\_Start\BundleConfig.cs dan periksa RegisterBundles metode yang digunakan untuk membuat, mendaftarkan, dan mengonfigurasi bundel. Kode berikut menunjukkan bagian dari RegisterBundles metode .

public static void RegisterBundles(BundleCollection bundles)
{
     bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                 "~/Scripts/jquery-{version}.js"));
         // Code removed for clarity.
}

Kode sebelumnya membuat bundel JavaScript baru bernama ~/bundles/jquery yang mencakup semua yang sesuai (yaitu debug atau dikurangi tetapi tidak .vsdoc) file di folder Skrip yang cocok dengan string kartubebas "~/Scripts/jquery-{version}.js". Untuk ASP.NET MVC 4, ini berarti dengan konfigurasi debug, file jquery-1.7.1.js akan ditambahkan ke bundel. Dalam konfigurasi rilis, jquery-1.7.1.min.js akan ditambahkan. Kerangka kerja bundling mengikuti beberapa konvensi umum seperti:

  • Memilih file ".min" untuk rilis saat FileX.min.js dan FileX.js ada.
  • Memilih versi non ".min" untuk debug.
  • Mengabaikan file "-vsdoc" (seperti jquery-1.7.1-vsdoc.js), yang hanya digunakan oleh IntelliSense.

Pencocokan {version} kartubebas yang ditunjukkan di atas digunakan untuk secara otomatis membuat bundel jQuery dengan versi jQuery yang sesuai di folder Skrip Anda. Dalam contoh ini, menggunakan wild card memberikan manfaat berikut:

  • Memungkinkan Anda menggunakan NuGet untuk memperbarui ke versi jQuery yang lebih baru tanpa mengubah kode bundling sebelumnya atau referensi jQuery di halaman tampilan Anda.
  • Secara otomatis memilih versi lengkap untuk konfigurasi debug dan versi ".min" untuk build rilis.

Menggunakan CDN

Kode berikut mengganti bundel jQuery lokal dengan bundel jQuery CDN.

public static void RegisterBundles(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 CDN
    var jqueryCdnPath = "https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";

    bundles.Add(new ScriptBundle("~/bundles/jquery",
                jqueryCdnPath).Include(
                "~/Scripts/jquery-{version}.js"));

    // Code removed for clarity.
}

Dalam kode di atas, jQuery akan diminta dari CDN saat dalam mode rilis dan versi debug jQuery akan diambil secara lokal dalam mode debug. Saat menggunakan CDN, Anda harus memiliki mekanisme fallback jika permintaan CDN gagal. Fragmen markup berikut dari akhir file tata letak memperlihatkan skrip yang ditambahkan untuk meminta jQuery jika CDN gagal.

</footer>

        @Scripts.Render("~/bundles/jquery")

        <script type="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>

Membuat Bundel

Metode kelas IncludeBundel mengambil array string, di mana setiap string adalah jalur virtual ke sumber daya. Kode berikut dari RegisterBundles metode dalam file App\_Start\BundleConfig.cs menunjukkan bagaimana beberapa file ditambahkan ke bundel:

bundles.Add(new StyleBundle("~/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"));

Metode kelas IncludeDirectoryBundel disediakan untuk menambahkan semua file dalam direktori (dan secara opsional semua subdirektori) yang cocok dengan pola pencarian. API kelas IncludeDirectoryBundel ditunjukkan di bawah ini:

public Bundle IncludeDirectory(
    string directoryVirtualPath,  // The Virtual Path for the directory.
    string searchPattern)         // The search pattern.

public Bundle IncludeDirectory(
    string directoryVirtualPath,  // The Virtual Path for the directory.
    string searchPattern,         // The search pattern.
    bool searchSubdirectories)    // true to search subdirectories.

Bundel direferensikan dalam tampilan menggunakan metode Render, (Styles.Render untuk CSS dan Scripts.Render untuk JavaScript). Markup berikut dari file Views\Shared\_Layout.cshtml memperlihatkan bagaimana tampilan proyek internet ASP.NET default mereferensikan bundel CSS dan JavaScript.

<!DOCTYPE html>
<html lang="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>

Perhatikan metode Render mengambil array string, sehingga Anda dapat menambahkan beberapa bundel dalam satu baris kode. Anda umumnya ingin menggunakan metode Render yang membuat HTML yang diperlukan untuk mereferensikan aset. Anda dapat menggunakan Url metode untuk menghasilkan URL ke aset tanpa markup yang diperlukan untuk mereferensikan aset. Misalkan Anda ingin menggunakan atribut asinkron HTML5 baru. Kode berikut menunjukkan cara mereferensikan modernizr menggunakan Url metode .

<head>
    @*Markup removed for clarity*@
    <meta charset="utf-8" />
    <title>@ViewBag.Title - MVC 4 B/M</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />
    @Styles.Render("~/Content/css")

   @* @Scripts.Render("~/bundles/modernizr")*@

    <script src='@Scripts.Url("~/bundles/modernizr")' async> </script>
</head>

Menggunakan Karakter KartuBebas "*" untuk Memilih File

Jalur virtual yang ditentukan dalam Include metode dan pola pencarian dalam IncludeDirectory metode dapat menerima satu karakter kartubebas "*" sebagai awalan atau akhiran ke di segmen jalur terakhir. String pencarian tidak peka huruf besar/kecil. Metode IncludeDirectory ini memiliki opsi untuk mencari subdirektori.

Pertimbangkan proyek dengan file JavaScript berikut:

  • Scripts\Common\AddAltToImg.js
  • Scripts\Common\ToggleDiv.js
  • Scripts\Common\ToggleImg.js
  • Scripts\Common\Sub1\ToggleLinks.js

dir imag

Tabel berikut ini memperlihatkan file yang ditambahkan ke bundel menggunakan wildcard seperti yang diperlihatkan:

Panggil File Ditambahkan atau Pengecualian Dimunculkan
Include("~/Scripts/Common/*.js") AddAltToImg.js, ToggleDiv.js, ToggleImg.js
Include("~/Scripts/Common/T*.js") Pengecualian pola tidak valid. Karakter kartubebas hanya diperbolehkan pada awalan atau akhiran.
Include("~/Scripts/Common/*og.*") Pengecualian pola tidak valid. Hanya satu karakter kartubebas yang diizinkan.
Include("~/Scripts/Common/T*") ToggleDiv.js, ToggleImg.js
Include("~/Scripts/Common/*") Pengecualian pola tidak valid. Segmen wildcard murni tidak valid.
IncludeDirectory("~/Scripts/Common", "T*") ToggleDiv.js, ToggleImg.js
IncludeDirectory("~/Scripts/Common", "T*", true) ToggleDiv.js, ToggleImg.js, ToggleLinks.js

Secara eksplisit menambahkan setiap file ke bundel umumnya lebih disukai daripada pemuatan file wildcard karena alasan berikut:

  • Menambahkan skrip dengan wildcard secara default untuk memuatnya dalam urutan alfabet, yang biasanya bukan yang Anda inginkan. File CSS dan JavaScript sering kali perlu ditambahkan dalam urutan tertentu (non-alfabet). Anda dapat mengurangi risiko ini dengan menambahkan implementasi IBundleOrderer kustom, tetapi secara eksplisit menambahkan setiap file kurang rawan kesalahan. Misalnya, Anda dapat menambahkan aset baru ke folder di masa mendatang yang mungkin mengharuskan Anda mengubah implementasi IBundleOrderer Anda.

  • Melihat file tertentu yang ditambahkan ke direktori menggunakan pemuatan kartubebas dapat disertakan dalam semua tampilan yang merujuk pada bundel tersebut. Jika tampilan skrip tertentu ditambahkan ke bundel, Anda mungkin mendapatkan kesalahan JavaScript pada tampilan lain yang mereferensikan bundel.

  • File CSS yang mengimpor file lain menghasilkan file yang diimpor dimuat dua kali. Misalnya, kode berikut membuat bundel dengan sebagian besar file CSS tema UI jQuery yang dimuat dua kali.

    bundles.Add(new StyleBundle("~/jQueryUI/themes/baseAll")
        .IncludeDirectory("~/Content/themes/base", "*.css"));
    

    Pemilih kartubebas "*.css" membawa setiap file CSS di folder, termasuk file Content\themes\base\jquery.ui.all.css . File jquery.ui.all.css mengimpor file CSS lainnya.

Penembolokan Bundel

Bundel mengatur Http Expires Header satu tahun dari saat bundel dibuat. Jika Anda menavigasi ke halaman yang dilihat sebelumnya, Fiddler menunjukkan IE tidak membuat permintaan kondisional untuk bundel, yaitu, tidak ada permintaan HTTP GET dari IE untuk bundel dan tidak ada respons HTTP 304 dari server. Anda dapat memaksa IE untuk membuat permintaan kondisional untuk setiap bundel dengan kunci F5 (menghasilkan respons HTTP 304 untuk setiap bundel). Anda dapat memaksa refresh penuh dengan menggunakan ^F5 (menghasilkan respons HTTP 200 untuk setiap bundel.)

Gambar berikut ini memperlihatkan tab Penembolokan panel respons Fiddler:

gambar penembolokan fiddler

Permintaan
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
adalah untuk bundel AllMyScripts dan berisi pasangan string kueri v=r0sLDicvP58AIXN\_mc3QdyVvVj5euZNzdsa2N1PKvb81. String kueri v memiliki token nilai yang merupakan pengidentifikasi unik yang digunakan untuk penembolokan. Selama bundel tidak berubah, aplikasi ASP.NET akan meminta bundel AllMyScripts menggunakan token ini. Jika ada file dalam bundel yang berubah, kerangka kerja pengoptimalan ASP.NET akan menghasilkan token baru, menjamin bahwa permintaan browser untuk bundel akan mendapatkan bundel terbaru.

Jika Anda menjalankan alat pengembang IE9 F12 dan menavigasi ke halaman yang dimuat sebelumnya, IE salah menampilkan permintaan GET kondisional yang dibuat untuk setiap bundel dan server yang mengembalikan HTTP 304. Anda dapat membaca mengapa IE9 memiliki masalah menentukan apakah permintaan bersyarat dibuat dalam entri blog Menggunakan CDN dan Kedaluwarsa untuk Meningkatkan Performa Situs Web.

LESS, CoffeeScript, SCSS, Sass Bundling.

Kerangka kerja bundling dan minifikasi menyediakan mekanisme untuk memproses bahasa perantara seperti SCSS, Sass, LESS atau Coffeescript, dan menerapkan transformasi seperti minifikasi ke bundel yang dihasilkan. Misalnya, untuk menambahkan file .less ke proyek MVC 4 Anda:

  1. Buat folder untuk konten LESS Anda. Contoh berikut menggunakan folder Content\MyLess .

  2. Tambahkan paket NuGet .lesstanpa titik ke proyek Anda.
    Penginstalan tanpa titik NuGet

  3. Tambahkan kelas yang mengimplementasikan antarmuka IBundleTransform . Untuk transformasi .less, tambahkan kode berikut ke proyek Anda.

    using System.Web.Optimization;
    
    public class LessTransform : IBundleTransform
    {
        public void Process(BundleContext context, BundleResponse response)
        {
            response.Content = dotless.Core.Less.Parse(response.Content);
            response.ContentType = "text/css";
        }
    }
    
  4. Buat bundel file LESS dengan LessTransform dan transformasi CssMinify . Tambahkan kode berikut ke RegisterBundles metode di file App\_Start\BundleConfig.cs .

    var lessBundle = new Bundle("~/My/Less").IncludeDirectory("~/My", "*.less");
    lessBundle.Transforms.Add(new LessTransform());
    lessBundle.Transforms.Add(new CssMinify());
    bundles.Add(lessBundle);
    
  5. Tambahkan kode berikut ke tampilan apa pun yang mereferensikan bundel LESS.

    @Styles.Render("~/My/Less");
    

Pertimbangan Bundel

Konvensi yang baik untuk diikuti saat membuat bundel adalah menyertakan "bundel" sebagai awalan dalam nama bundel. Ini akan mencegah kemungkinan konflik perutean.

Setelah Anda memperbarui satu file dalam bundel, token baru dibuat untuk parameter string kueri bundel dan bundel lengkap harus diunduh saat klien meminta halaman yang berisi bundel. Dalam markup tradisional di mana setiap aset dicantumkan satu per satu, hanya file yang diubah yang akan diunduh. Aset yang sering berubah mungkin bukan kandidat yang baik untuk bundling.

Bundling dan minifikasi terutama meningkatkan waktu pemuatan permintaan halaman pertama. Setelah halaman web diminta, browser menyimpan aset (JavaScript, CSS, dan gambar) sehingga bundling dan minifikasi tidak akan memberikan peningkatan performa apa pun saat meminta halaman yang sama, atau halaman di situs yang sama yang meminta aset yang sama. Jika Anda tidak mengatur header kedaluwarsa dengan benar pada aset Anda, dan Anda tidak menggunakan bundling dan minifikasi, heuristik kesegaran browser akan menandai aset basi setelah beberapa hari dan browser akan memerlukan permintaan validasi untuk setiap aset. Dalam hal ini, bundling dan minifikasi memberikan peningkatan performa setelah permintaan halaman pertama. Untuk detailnya, lihat blog Menggunakan CDN dan Kedaluwarsa untuk Meningkatkan Performa Situs Web.

Batasan browser enam koneksi simultan per setiap nama host dapat dimitigasi dengan menggunakan CDN. Karena CDN akan memiliki nama host yang berbeda dari situs hosting Anda, permintaan aset dari CDN tidak akan dihitung terhadap batas enam koneksi simultan ke lingkungan hosting Anda. CDN juga dapat memberikan keunggulan penembolokan paket umum dan penembolokan tepi.

Bundel harus dipartisi oleh halaman yang membutuhkannya. Misalnya, templat ASP.NET MVC default untuk aplikasi internet membuat bundel Validasi jQuery yang terpisah dari jQuery. Karena tampilan default yang dibuat tidak memiliki input dan tidak memposting nilai, tampilan tersebut tidak menyertakan bundel validasi.

Namespace System.Web.Optimization layanan diimplementasikan dalam System.Web.Optimization.dll. Ini memanfaatkan pustaka WebGrease (WebGrease.dll) untuk kemampuan minifikasi, yang pada gilirannya menggunakan Antlr3.Runtime.dll.

Saya menggunakan Twitter untuk membuat posting cepat dan berbagi tautan. Handel Twitter saya adalah: @RickAndMSFT

Sumber Daya Tambahan:

Kontributor