Exportar (0) Imprimir
Expandir Tudo

ASP.NET - Uso de Bundle e Minification no ASP.NET MVC 4 e ASP.NET Web Forms 4.5

Por Renato Haddad

Abril, 2013

Dn168847.060DE5057573180CEC6D227C6D3E2207(pt-br,MSDN.10).png

Você já pensou na quantidade de bytes trafegados entre o servidor e o cliente a cada solicitação? Será que há como diminuir esta quantidade, ou melhor ainda, colocar parte dos dados no cache do servidor?

Neste artigo vou explicar passo a passo como preparar o seu projeto para aplicar um novo conceito chamado Bundle e Minification, ambos conceitos novos para qualquer projeto escrito em ASP.NET MVC 4 e ASP.NET Web Forms 4.5. Vou desenvolver um projeto novo em ASP.NET MVC 4, mas você pode aplicar exatamente os passos para o ASP.NET Web forms 4.5.

Antes de mais nada, sabemos que há anos toda a parte de design dos sites ocorre através de arquivos CSS. Não basta ter um HTML 5 perfeito, com tudo o que esta versão nos oferece, é fundamental um bom CSS para fazer o show a parte. Então, é comum num projeto de tamanho médio ter diversos arquivos CSS, a fim de customizar as páginas do site. Outro fator que todo desenvolvedor WEB deve saber, é que o uso de JavaScript, isso mesmo JavaScript, está sendo cada vez mais usado. Aliás, é praticamente impossível hoje em dia uma aplicação WEB não usar JavaScript. Isto tudo porque o processamento do código será realizado no lado do cliente. E como ficam as solicitações no servidor? A palavra chave aqui é Jquery requisitando serviços escritos em Web API, o qual retornam JSON e XML nativamente, ou ainda We Services ou WCF. Sendo assim, quer dizer que preciso aprender JavaScript, Jquery, HTML 5 e CSS para um bom projeto WEB? Sim, e além disso, C# 5, Entity Framework 5, entre outras tecnologias.

Vamos iniciar o Visual Studio .NET 2012 (com os 2 updates instalados). Caso tenha a versão Express, você pode aplicar exatamente os mesmos recursos. Selecione New Project, e no template Visual C# / Web / ASP.NET MVC 4 Web Application. O nome do projeto é MSDN_Bundle e você pode cria-lo em qualquer diretório, conforme a figura 1.

Dn168847.3AFDEA1F74946C0B50096F26F6EA9895(pt-br,MSDN.10).png

Figura 1 – Novo projeto

Clique no botão OK e na próxima tela, selecione o template Internet Application, conforme a figura 2.`

Dn168847.FC143298FFA71CC1446A2E0838E7FE8A(pt-br,MSDN.10).png

Figura 2 – Template de Internet Application

Clique no botão OK e aguarde a criação da estrutura do projeto. Abra o Solution Explorer, expanda a pasta Content, o qual contém a pasta themes. Pela estrutura do projeto aqui estão armazenados todos os arquivos CSS. Note que há o arquivo Site.css, conforme a figura 3, onde contém todas as notações necessárias para o layout/design do site. No entanto, como citei anteriormente, muitos projetos já usam jquery, então este template já contém todos os arquivos CSS para cada tipo de controle do jqueryui (responsável pela interface de usuário). Todos estão contidos na pasta Content/themes/base. Como se não bastasse, dentro da pasta base, há outra chamada Minified com diversos outros arquivos CSS para o jqueryui. No entanto, os arquivos desta pasta tem uma extensão .min.css. Abra um destes arquivos e veja os códigos escritos, tanto para o .css quanto para o .min.css.

Dn168847.8D7FEB2E33E1415C490ADD0C7B391B3C(pt-br,MSDN.10).png

Figura 3 – Arquivos CSS no projeto


Vamos falar um pouco sobre os arquivos de scripts. Abra a pasta Scripts e veja a quantidade de arquivos .js contidos no projeto, conforme a figura 4. Mas porquê há tantos arquivos se não usarei? Na verdade o template já adiciona ao projeto todos os arquivos em javascript básicos necessários para a execução do mesmo. Muitos você nem sabe que são usados, e quando trabalhar com Jquery, JqueryUI e validação de dados com Data Annotations, todos estes são requisitados. Enfim, o foco aqui não é questionar o que faz cada arquivo, e sim como administrá-los.

Dn168847.78A68698ED4F129DD992DBEDB6B19186(pt-br,MSDN.10).png

Figura 4 – Arquivos Javascript no projeto

Configuração do Bundle

Você sabe muito bem que nem todos os arquivos você pode usar nas páginas, você pode ter diversos arquivos CSS e JS e usá-los de acordo a necessidade, seja dinamicamente ou não. Como que isto ocorre nos bastidores? Abra a pasta App_Start e veja que há diversos arquivos de configuração, então, abra o arquivo BundleConfig.cs, conforme a listagem a seguir. Veja que há uma referência ao namespace System.Web.Optimization, que nos permite otimizar as referências aos arquivos. Primeiro, o nome da classe chama-se BundleConfig e há um método estático chamado RegisterBundles que recebe como parâmetro uma coleção de Bundles (BundleCollection).

using System.Web;
using System.Web.Optimization;

namespace MSDN_Bundle
{
    public class BundleConfig
    {
        // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

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

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.unobtrusive*",
                        "~/Scripts/jquery.validate*"));

            // Use the development version of Modernizr to develop with and learn from. Then, when you're
            // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));

            bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

            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"));
        }
    }
}

Note que a cada linha é adicionado um elemento à coleção (bundle.Add) onde você pode referenciar um ScriptBundle ou um StyleBundle.

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

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

Nesta notação é preciso informar o nome virtual ("~/bundles/jquery") que será criado em tempo de execução numa pasta chamada bundles abaixo do diretório raiz, seguido do método Include, onde você fornece toda a lista de arquivos separados por vírgula. Esta estrutura vale tanto para script quanto style. Observe a lista completa de arquivos na listagem anterior e veja que a referência ao arquivo virtual “~/Content/themes/base/css” contém muitos arquivos físicos contidos na pasta “~/Content/themes/base/”.

Outra notação a ser aprendida é o {version}, que significa qualquer versão. Por exemplo, em “~/Scripts/jquery-{version}.js” significa que qualquer arquivo chamado jquery-1.8.2.js, jquery-1.8.2.intellisense.js ou jquery.1.8.2.min.js serão adicionados ao mesmo.

Sendo assim, você já nota que uma das vantagens disso é que se houver qualquer outro arquivo novo adicionado à pasta, não é preciso fazer nada no seu projeto, o arquivo será referenciado ao projeto automaticamente. Outra vantagem é que se você atualizar a versão do jquery, também não é preciso alterar nada no projeto. Caso queira testar esta atualização da versão do jquery e jqueryui, use o Nuget (update-package nomedopacote).


Resgistro do Bundle

Muito bem, temos o arquivo BundleConfig.cs e como que este é invocado? Tudo começa no arquivo Global.asax.cs, abra-o e veja que há um método chamado Application_Start que é executado toda vez que a aplicação é iniciada. Veja na listagem a seguir que existe uma chamada para a classe BundleConfig.RegisterBundles passando a lista de BundleTables.Bundles. Pronto, basta esta chamada para que a classe seja invocada. Durante os vossos testes, pode comentar esta linha a cada teste para ver o resultado.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
    }
}

Uso do Bundle

Agora chegou o momento de usarmos o Bundle. Nos projetos é comum colocarmos as referências dos arquivos CSS e JS na master-page. No caso deste projeto MVC 4, abra o arquivo _Layout.cshtml na pasta Views/Shared. Note que dentro da sessão head há duas referências de @Styles.Render e @Scripts.Render, e ao final do arquivo tem outro @Scripts.Render. Os nomes fornecidos são exatamente os nomes virtuais declarados na estrutura do Bundle.Config.

<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</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")
</head>
...
@Scripts.Render("~/bundles/jquery")

Execução do Bundle

Para entender o funcionamento do Bundle e do Minification é preciso executar o projeto. Pressione F5 para abrir o projeto no navegador. Usarei o IE9, e quando o projeto estiver aberto no navegador, pressione F12 para abrir as ferramentas de desenvolvedor do IE9. Clique no botão Rede / Iniciar Captura. A partir de agora, tudo o que você fizer no navegador, será capturado por esta ferramenta. Então, pressione F5 para atualizar a página. Conforme a figura 5, veja todos os arquivos carregados, sendo que destacamos um .css e dois .js.

Dn168847.ED785A86C06BA288C4DB5E505F3B22F8(pt-br,MSDN.10).png

Figura 5 – Execução no navegador

Clique na guia Script e abra o ícone para listar quais arquivos .js estão carregados. Conforme a figura 6, temos dois arquivos. Caso queira visualizar o conteúdo, basta clicar no mesmo.

Dn168847.8CC0A3C7612733408AEC44E636489DF6(pt-br,MSDN.10).png

Figura 6 – Arquivos de Scripts

Até aqui você percebeu que mesmo tendo vários arquivos citados no arquivo BundleConfig.cs, nem todos foram carregados. Então, no arquivo _Layout.cshtml e adicione a referência ao @Styles.Render("~/Content/themes/base/css").

<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />
    @Styles.Render("~/Content/css")
    @Styles.Render("~/Content/themes/base/css")
    @Scripts.Render("~/bundles/modernizr")
</head>

Execute a aplicação no navegador novamente e conforme a figura 7, veja quantos arquivos foram carregados. Navegue pelo site, clique nas outras opções do menu (Contact e About) e observe que todos os arquivos são carregados novamente. O tempo decorrido em milissegundos é rápido porque estão no cache, porém como melhorar mais ainda este tempo de resposta?

Dn168847.A7E3F0C005C15B5C4EBBF840C8B11642(pt-br,MSDN.10).png

Figura 7 – Lista de arquivos carregados

Não é justo carregar todos estes arquivos a cada requisição, correto? Mas infelizmente é assim, então, o que o time de ASP.NET fez para melhorar a performance? Abra o arquivo Global.asax.cs e adicione o comando BundleTable.EnableOptimizations = true; ao final do método Application_Start. Isto fará com que os arquivos sejam compactados e seja gerado um token para cada conjunto de bundle declarado. Isto é o conceito de minification, e use e abuse deste conceito.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();

    BundleTable.EnableOptimizations = true;
}

Execute novamente o projeto no navegador, use o F12 para rastrear a captura do tráfego, conforme a figura 8. Note que há uma grande diferença na quantidade de arquivos trafegados, temos apenas dois CSS e dois JS.

Dn168847.01500506F387E9C647808280117E5834(pt-br,MSDN.10).png

Figura 8 – Arquivos compactados

Clique na guia Script, selecione o aquivo jquery, conforme a figura 9, e observe que todos os arquivos jquery*.js estão compactados em apenas um arquivo. Você pode checar os demais arquivos, tanto JS quanto CSS que verá a mesma notação.

Dn168847.7351E3E46E6325BB12FDCEB1863886FE(pt-br,MSDN.10).png

Figura 9 – Arquivo JS compactado

Como exemplo, clique na guia CSS e veja a lista dos CSSs compactados contendo os respectivos tokens de cada um.

Dn168847.34274A02E9EBB5332077841C7F50A82A(pt-br,MSDN.10).png

F10 – CSS compactado

A principal vantagem é que o uso do bundle e minification é que o arquivo ficará no cache do servidor por um ano. Toda requisição que bater no servidor será comparada com o token gerado, caso tenha alguma alteração, o arquivo é enviado ao cliente.

O grande desafio dos desenvolvedores é tornar as aplicações WEB mais rápidas, deixando o internauta focado na aplicação em si, não esperando o servidor responder as requisições. Estes recursos de Bundle e Minification nos ajudará em muito neste aspecto. Bons estudos e sucesso nos projetos.

Sobre o Autor

Renato Haddad (rehaddad@msn.comwww.renatohaddad.com ) é MVP, MCT, MCPD e MCTS, palestrante em eventos da Microsoft em diversos países, ministra treinamentos focados em produtividade com o VS.NET 2010/2012, ASP.NET 4, ASP.NET MVC, Entity Framework, Reporting Services, Windows Phone e Windows 8. Visite o blog http://weblogs.asp.net/renatohaddad.

Mostrar:
© 2014 Microsoft