Creazione di bundle e minimizzazione
L'aggregazione e la minificazione sono due tecniche che è possibile usare in ASP.NET 4,5 per migliorare il tempo di caricamento delle richieste. Il raggruppamento e la minificazione migliorano il tempo di caricamento riducendo il numero di richieste al server e riducendo le dimensioni degli asset richiesti , ad esempio CSS e JavaScript.
La maggior parte dei principali browser correnti limita il numero di connessioni simultanee per ogni nome host a sei. Ciò significa che durante l'elaborazione di sei richieste, le richieste aggiuntive per gli asset in un host verranno accodate dal browser. Nell'immagine seguente, le schede di rete degli strumenti di sviluppo IE F12 mostrano la tempistica per gli asset richiesti dalla visualizzazione Informazioni di un'applicazione di esempio.
Le barre grigie mostrano l'ora in cui la richiesta viene accodata dal browser in attesa del limite di connessione di sei. La barra gialla è il tempo di richiesta per il primo byte, ovvero il tempo impiegato per inviare la richiesta e ricevere la prima risposta dal server. Le barre blu mostrano il tempo impiegato per ricevere i dati di risposta dal server. È possibile fare doppio clic su un asset per ottenere informazioni dettagliate sulla tempistica. Ad esempio, l'immagine seguente mostra i dettagli relativi al tempo per il caricamento del file /Script/MyScripts/JavaScript6.js .
L'immagine precedente mostra l'evento Start , che fornisce l'ora in cui la richiesta è stata accodata a causa del limite del browser al numero di connessioni simultanee. In questo caso, la richiesta è stata accodata per 46 millisecondi in attesa del completamento di un'altra richiesta.
Impacchettare
Il raggruppamento è una nuova funzionalità in ASP.NET 4.5 che semplifica la combinazione o l'aggregazione di più file in un singolo file. È possibile creare bundle CSS, JavaScript e altri bundle. Meno file significano meno richieste HTTP e che possono migliorare le prestazioni del carico di prima pagina.
L'immagine seguente mostra la stessa visualizzazione temporale della visualizzazione Informazioni mostrata in precedenza, ma questa volta con raggruppamento e minificazione abilitata.
Minimizzazione
La minificazione esegue diverse ottimizzazioni di codice per script o css, ad esempio la rimozione di spazi vuoti e commenti non necessari e l'abbreviazione dei nomi delle variabili a un carattere. Prendere in considerazione la funzione JavaScript seguente.
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/, ''));
}
Dopo la minificazione, la funzione viene ridotta al seguente:
AddAltToImg = function (n, t) { var i = $(n, t); i.attr("alt", i.attr("id").replace(/ID/, "")) }
Oltre a rimuovere i commenti e gli spazi vuoti non necessari, i parametri e i nomi delle variabili seguenti sono stati rinominati (abbreviati) come segue:
Originale | Renamed |
---|---|
imageTagAndImageID | n |
imageContext | t |
imageElement | i |
Impatto del raggruppamento e della minificazione
La tabella seguente mostra diverse differenze importanti tra l'elenco di tutti gli asset singolarmente e l'uso del raggruppamento e della minificazione (B/M) nel programma di esempio.
Uso di B/M | Senza B/M | Modifica | |
---|---|---|---|
Richieste di file | 9 | 34 | 256% |
KB Inviato | 3.26 | 11.92 | 266% |
KB ricevuta | 388.51 | 530 | 36% |
Tempo di caricamento | 510 MS | 780 MS | 53% |
I byte inviati hanno avuto una riduzione significativa con raggruppamento come browser sono abbastanza dettagliati con le intestazioni HTTP applicate alle richieste. La riduzione dei byte ricevuti non è così grande perché i file più grandi (Scripts\jquery-ui-1.8.11.min.js e Scripts\jquery-1.7.1.min.js) sono già minificati. Nota: i tempi nel programma di esempio hanno usato lo strumento Fiddler per simulare una rete lenta. Dal menu Regole di Fiddler selezionare Prestazioni e quindi Simulare velocità del modem.
Debug di JavaScript in bundle e minified
È facile eseguire il debug di JavaScript in un ambiente di sviluppo (dove l'elemento di compilazione nel file diWeb.config è impostato su debug="true"
) perché i file JavaScript non sono raggruppati o minificati. È anche possibile eseguire il debug di una build di versione in cui i file JavaScript vengono raggruppati e minificati. Usando gli strumenti di sviluppo IE F12, eseguire il debug di una funzione JavaScript inclusa in un bundle minified usando l'approccio seguente:
- Selezionare la scheda Script e quindi selezionare il pulsante Avvia debug .
- Selezionare il bundle contenente la funzione JavaScript che si vuole eseguire il debug usando il pulsante asset.
- Formattare javaScript minified selezionando Selezionare Formato JavaScript.
- Nella casella di input dello script di ricerca selezionare il nome della funzione da eseguire il debug. Nell'immagine seguente , AddAltToImg è stato immesso nella casella di input dello script di ricerca .
Per altre informazioni sul debug con gli strumenti di sviluppo F12, vedere l'articolo MSDN Usando gli strumenti per sviluppatori F12 per eseguire il debug di errori JavaScript.
Controllo del raggruppamento e della minificazione
Il raggruppamento e la minificazione sono abilitati o disabilitati impostando il valore dell'attributo di debug nell'elemento di compilazione nel file Web.config . Nel codice XML seguente, è impostato su true in debug
modo che la creazione di aggregazioni e la minificazione sia disabilitata.
<system.web>
<compilation debug="true" />
<!-- Lines removed for clarity. -->
</system.web>
Per abilitare il raggruppamento e la minificazione, impostare il debug
valore su "false". È possibile eseguire l'override dell'impostazione Web.config con la EnableOptimizations
proprietà nella BundleTable
classe. Il codice seguente consente di raggruppare e minificare e eseguire l'override di qualsiasi impostazione nel file diWeb.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;
}
Nota
A meno che EnableOptimizations
non sia true
o l'attributo di debug nell'elemento di compilazione nel file Web.config sia impostato su false
, i file non verranno raggruppati o minificati. Inoltre, la versione min dei file non verrà usata, verranno selezionate le versioni di debug complete. EnableOptimizations
esegue l'override dell'attributo debug nell'elemento di compilazione nel file diWeb.config
Uso del raggruppamento e della minificazione con Web Forms ASP.NET e pagine Web
- Per le pagine Web, vedere la voce di blog Aggiunta dell'ottimizzazione Web a un sito pagine Web.
- Per Web Forms, vedere la voce di blog Aggiunta di bundling e minification a Web Forms.
Uso del raggruppamento e della minificazione con ASP.NET MVC
In questa sezione verrà creato un progetto ASP.NET MVC per esaminare l'aggregazione e la minificazione. Creare prima di tutto un nuovo progetto Internet MVC ASP.NET denominato MvcBM senza modificare alcuna delle impostazioni predefinite.
Aprire il file App\_Start\BundleConfig.cs ed esaminare il RegisterBundles
metodo usato per creare, registrare e configurare i bundle. Il codice seguente mostra una parte del RegisterBundles
metodo.
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
}
Il codice precedente crea un nuovo bundle JavaScript denominato ~/bundles/jquery che include tutti gli elementi appropriati ,ovvero debug o minified ma non .file vsdoc) nella cartella Script che corrispondono alla stringa jolly "~/Scripts/jquery-{version}.js". Per ASP.NET MVC 4, questo significa che con una configurazione di debug, il file jquery-1.7.1.js verrà aggiunto al bundle. In una configurazione di versione, jquery-1.7.1.min.js verrà aggiunto. Il framework di raggruppamento segue diverse convenzioni comuni, ad esempio:
- Selezionare il file ".min" per la versione quando FileX.min.js e FileX.js esiste.
- Selezione della versione non ".min" per il debug.
- Ignorando i file "-vsdoc" (ad esempio jquery-1.7.1-vsdoc.js), usati solo da IntelliSense.
La {version}
corrispondenza con caratteri jolly mostrati sopra viene usata per creare automaticamente un bundle jQuery con la versione appropriata di jQuery nella cartella Script . In questo esempio, l'uso di una carta jolly offre i vantaggi seguenti:
- Consente di usare NuGet per aggiornare a una versione jQuery più recente senza modificare il codice di raggruppamento precedente o i riferimenti jQuery nelle pagine di visualizzazione.
- Seleziona automaticamente la versione completa per le configurazioni di debug e la versione "min" per le build di versione.
Uso di una rete CDN
Il codice seguente sostituisce il bundle jQuery locale con un bundle jQuery della rete 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.
}
Nel codice precedente, jQuery verrà richiesto dalla rete CDN durante la modalità di rilascio e la versione di debug di jQuery verrà recuperata localmente in modalità di debug. Quando si usa una rete CDN, è necessario disporre di un meccanismo di fallback nel caso in cui la richiesta della rete CDN abbia esito negativo. Il frammento di markup seguente dalla fine del file di layout mostra lo script aggiunto alla richiesta jQuery, se la rete CDN avrà esito negativo.
</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>
Creazione di un bundle
Il metodo della classe Include
Bundle accetta una matrice di stringhe, in cui ogni stringa è un percorso virtuale per la risorsa. Il codice seguente dal RegisterBundles
metodo nel file App\_Start\BundleConfig.cs mostra come vengono aggiunti più file a un bundle:
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"));
Il metodo della classe IncludeDirectory
Bundle viene fornito per aggiungere tutti i file in una directory (e facoltativamente tutte le sottodirectory) che corrispondono a un modello di ricerca. L'API della classe IncludeDirectory
Bundle è illustrata di seguito:
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.
I bundle vengono a cui si fa riferimento nelle visualizzazioni usando il metodo Render, (Styles.Render
per CSS e Scripts.Render
per JavaScript). Il markup seguente del file Views\Shared\_Layout.cshtml mostra come le visualizzazioni predefinite ASP.NET progetti Internet fanno riferimento ai bundle CSS e 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>
Si noti che i metodi di rendering accettano una matrice di stringhe, quindi è possibile aggiungere più bundle in una riga di codice. In genere si vuole usare i metodi di rendering che creano il codice HTML necessario per fare riferimento all'asset. È possibile usare il Url
metodo per generare l'URL nell'asset senza il markup necessario per fare riferimento all'asset. Si supponga di voler usare il nuovo attributo asincrono HTML5. Il codice seguente illustra come fare riferimento alla modernizzazione usando il Url
metodo .
<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>
Uso del carattere jolly "*" per selezionare i file
Il percorso virtuale specificato nel Include
metodo e il modello di ricerca nel IncludeDirectory
metodo può accettare un carattere jolly "*" come prefisso o suffisso nell'ultimo segmento di percorso. La stringa di ricerca è senza distinzione tra maiuscole e minuscole. Il IncludeDirectory
metodo ha la possibilità di cercare sottodirectory.
Prendere in considerazione un progetto con i file JavaScript seguenti:
- Scripts\Common\AddAltToImg.js
- Scripts\Common\ToggleDiv.js
- Scripts\Common\ToggleImg.js
- Scripts\Common\Sub1\ToggleLinks.js
La tabella seguente mostra i file aggiunti a un bundle usando il carattere jolly, come illustrato di seguito:
Chiamare | File aggiunti o eccezioni generati |
---|---|
Include("~/Script/Common/*.js") | AddAltToImg.js,ToggleDiv.js, ToggleImg.js |
Include("~/Script/Common/T*.js") | Eccezione di modello non valida. Il carattere jolly è consentito solo sul prefisso o sul suffisso. |
Include("~/Scripts/Common/*og.*") | Eccezione di modello non valida. È consentito un solo carattere jolly. |
Include("~/Script/Common/T*") | ToggleDiv.js, ToggleImg.js |
Include("~/Script/Common/*") | Eccezione di modello non valida. Un segmento jolly puro non è valido. |
IncludeDirectory("~/Script/Common", "T*") | ToggleDiv.js, ToggleImg.js |
IncludeDirectory("~/Scripts/Common", "T*", true) | ToggleDiv.js,ToggleImg.js, ToggleLinks.js |
L'aggiunta esplicita di ogni file a un bundle è in genere la scelta preferita rispetto al caricamento con caratteri jolly dei file per i motivi seguenti:
L'aggiunta di script per impostazione predefinita con caratteri jolly per caricarli in ordine alfabetico, che in genere non è quello desiderato. I file CSS e JavaScript devono essere aggiunti spesso in un ordine specifico (non alfabetico). È possibile attenuare questo rischio aggiungendo un'implementazione IBundleOrderer personalizzata, ma aggiungendo in modo esplicito ogni file è meno soggetto a errori. Ad esempio, è possibile aggiungere nuovi asset a una cartella in futuro che potrebbe richiedere di modificare l'implementazione di IBundleOrderer .
Visualizzare file specifici aggiunti a una directory usando il caricamento con caratteri jolly possono essere inclusi in tutte le visualizzazioni che fanno riferimento a tale bundle. Se lo script specifico della visualizzazione viene aggiunto a un bundle, è possibile che venga visualizzato un errore JavaScript in altre visualizzazioni che fanno riferimento al bundle.
I file CSS che importano altri file generano due volte i file importati. Ad esempio, il codice seguente crea un bundle con la maggior parte dei file CSS del tema dell'interfaccia utente jQuery caricati due volte.
bundles.Add(new StyleBundle("~/jQueryUI/themes/baseAll") .IncludeDirectory("~/Content/themes/base", "*.css"));
Il selettore di caratteri jolly "*.css" porta in ogni file CSS nella cartella, incluso il file Content\themes\base\jquery.ui.all.css . Il file jquery.ui.all.css importa altri file CSS.
Memorizzazione nella cache dei bundle
I bundle impostano l'intestazione HTTP Scade un anno da quando viene creato il bundle. Se si passa a una pagina visualizzata in precedenza, Fiddler mostra che IE non effettua una richiesta condizionale per il bundle, ovvero non sono presenti richieste HTTP GET da Internet Explorer per i bundle e nessuna risposta HTTP 304 dal server. È possibile forzare L'internet Explorer a effettuare una richiesta condizionale per ogni bundle con la chiave F5 (con conseguente risposta HTTP 304 per ogni bundle). È possibile forzare un aggiornamento completo usando ^F5 (risultante una risposta HTTP 200 per ogni bundle).
L'immagine seguente mostra la scheda Memorizzazione nella cache del riquadro di risposta fiddler:
Richiesta.
http://localhost/MvcBM_time/bundles/AllMyScripts?v=r0sLDicvP58AIXN_mc3QdyVvVj5euZNzdsa2N1PKvb81
è per il bundle AllMyScripts e contiene una coppia di stringhe di query v=r0sLDicvP58AIXN\_mc3QdyVvVj5euZNzdsa2N1PKvb81. La stringa di query v ha un token di valore che è un identificatore univoco usato per la memorizzazione nella cache. Purché il bundle non cambi, l'applicazione ASP.NET richiederà il bundle AllMyScripts usando questo token. Se qualsiasi file nel bundle cambia, il framework di ottimizzazione ASP.NET genererà un nuovo token, garantendo che le richieste del browser per il bundle otterranno il bundle più recente.
Se si eseguono gli strumenti di sviluppo IE9 F12 e si passa a una pagina caricata in precedenza, IE visualizza in modo errato le richieste GET condizionali effettuate a ogni bundle e il server che restituisce HTTP 304. È possibile leggere il motivo per cui IE9 presenta problemi che determinano se una richiesta condizionale è stata effettuata nella voce di blog Usando le reti CDN e scade per migliorare le prestazioni del sito Web.
LESS, CoffeeScript, SCSS, Sass Bundling.
Il framework di aggregazione e minificazione fornisce un meccanismo per elaborare linguaggi intermedi, ad esempio SCSS, Sass, LESS o Coffeescript, e applicare trasformazioni come minification al bundle risultante. Ad esempio, per aggiungere file con estensione meno al progetto MVC 4:
Creare una cartella per il contenuto LESS. Nell'esempio seguente viene usata la cartella Content\MyLess .
Aggiungere il pacchetto NuGet senza punti al progetto.
Aggiungere una classe che implementa l'interfaccia IBundleTransform . Per la trasformazione .less, aggiungere il codice seguente al progetto.
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"; } }
Creare un bundle di file LESS con
LessTransform
e la trasformazione CssMinify . Aggiungere il codice seguente alRegisterBundles
metodo nel 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);
Aggiungere il codice seguente a tutte le visualizzazioni che fanno riferimento al bundle LESS.
@Styles.Render("~/My/Less");
Considerazioni sul bundle
Una buona convenzione da seguire quando si creano bundle consiste nell'includere "bundle" come prefisso nel nome del bundle. Ciò impedirà un possibile conflitto di routing.
Dopo aver aggiornato un file in un bundle, viene generato un nuovo token per il parametro stringa di query bundle e il bundle completo deve essere scaricato alla successiva richiesta di una pagina contenente il bundle. Nel markup tradizionale in cui ogni asset è elencato singolarmente, verrà scaricato solo il file modificato. Gli asset che cambiano spesso potrebbero non essere buoni candidati per il raggruppamento.
L'aggregazione e la minificazione migliorano principalmente il tempo di caricamento della prima richiesta di pagina. Dopo aver richiesto una pagina Web, il browser memorizza nella cache gli asset (JavaScript, CSS e immagini) in modo da non offrire un aumento delle prestazioni quando si richiede la stessa pagina o pagine nello stesso sito che richiede gli stessi asset. Se non si imposta correttamente l'intestazione di scadenza sugli asset e non si usa l'aggregazione e la minificazione, gli heuristici di aggiornamento dei browser contrassegneranno gli asset non aggiornati dopo alcuni giorni e il browser richiederà una richiesta di convalida per ogni asset. In questo caso, il raggruppamento e la minificazione forniscono un aumento delle prestazioni dopo la prima richiesta di pagina. Per informazioni dettagliate, vedere il blog Uso di reti CDN e scadenza per migliorare le prestazioni del sito Web.
La limitazione del browser di sei connessioni simultanee per ogni nome host può essere mitigata tramite una rete CDN. Poiché la rete CDN avrà un nome host diverso rispetto al sito di hosting, le richieste di asset dalla rete CDN non verranno conteggiati rispetto ai sei limiti di connessioni simultanee all'ambiente di hosting. Una rete CDN può anche offrire vantaggi comuni per la memorizzazione nella cache dei pacchetti e la memorizzazione nella cache perimetrale.
I bundle devono essere partizionati da pagine necessarie. Ad esempio, il modello di ASP.NET MVC predefinito per un'applicazione Internet crea un bundle jQuery Validation separato da jQuery. Poiché le visualizzazioni predefinite create non hanno alcun input e non pubblicano i valori, non includono il bundle di convalida.
Lo System.Web.Optimization
spazio dei nomi viene implementato in System.Web.Optimization.dll. Sfrutta la libreria WebGrease (WebGrease.dll) per le funzionalità di minification, che a sua volta usa Antlr3.Runtime.dll.
Uso Twitter per creare post rapidi e condividere collegamenti. Il mio handle Twitter è: @RickAndMSFT
Risorse aggiuntive
- Video:Bundling e Ottimizzazione di Howard Dierking
- Aggiunta dell'ottimizzazione Web a un sito di pagine Web.
- Aggiunta di bundling e minification a Web Forms.
- Implicazioni delle prestazioni di Bundling e Minification per l'esplorazione Web di Henrik F Nielsen@frystyk
- Uso di reti CDN e scadenza per migliorare le prestazioni del sito Web di Rick Anderson @RickAndMSFT
- Ridurre al minimo RTT (round trip time)
Autori di contributi
- Hao Kung
- Howard Dierking
- Diana LaRose
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per