Comment puis-je compresser et réduire automatiquement les fichiers JavaScript dans une application ASP.NET MVC?

StackOverflow https://stackoverflow.com/questions/1224292

Question

J'ai donc une application ASP.NET MVC qui référence un certain nombre de fichiers javascript à divers endroits (dans le maître du site et des références supplémentaires dans plusieurs vues également).

J'aimerais savoir s'il existe un moyen automatisé de compression et de réduction de ces références dans un seul fichier .js, dans la mesure du possible. Tels que cela ...

<script src="<%= ResolveUrl("~") %>Content/ExtJS/Ext.ux.grid.GridSummary/Ext.ux.grid.GridSummary.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/ext.ux.rating/ext.ux.ratingplugin.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/ext-starslider/ext-starslider.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/ext.ux.dollarfield.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/ext.ux.combobox.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/ext.ux.datepickerplus/ext.ux.datepickerplus-min.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/SessionProvider.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ExtJS/TabCloseMenu.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ActivityViewer/ActivityForm.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ActivityViewer/UserForm.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ActivityViewer/SwappedGrid.js" type="text/javascript"></script>
<script src="<%= ResolveUrl("~") %>Content/ActivityViewer/Tree.js" type="text/javascript"></script>

... pourrait être réduit à quelque chose comme ça ...

<script src="<%= ResolveUrl("~") %>Content/MyViewPage-min.js" type="text/javascript"></script>

Merci

Était-ce utile?

La solution

Personnellement, je pense que garder les fichiers séparés pendant le développement est inestimable et que pendant la production, c’est ce qui compte. J'ai donc modifié mon script de déploiement afin de le faire ci-dessus.

J'ai une section qui se lit comme suit:

<Target Name="BeforeDeploy">

        <ReadLinesFromFile File="%(JsFile.Identity)">
            <Output TaskParameter="Lines" ItemName="JsLines"/>
        </ReadLinesFromFile>

        <WriteLinesToFile File="Scripts\all.js" Lines="@(JsLines)" Overwrite="true"/>

        <Exec Command="java -jar tools\yuicompressor-2.4.2.jar Scripts\all.js -o Scripts\all-min.js"></Exec>

    </Target>

Et dans mon fichier de page maître, j'utilise:

if (HttpContext.Current.IsDebuggingEnabled)
   {%>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/jquery-1.3.2.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/jquery-ui-1.7.2.min.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/jquery.form.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/jquery.metadata.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/jquery.validate.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/additional-methods.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/form-interaction.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/morevalidation.js")%>"></script>
    <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/showdown.js") %>"></script>
<%
   }  else  {%> 
  <script type="text/javascript" src="<%=Url.UrlLoadScript("~/Scripts/all-min.js")%>"></script>
<% } %>

Le script de construction prend tous les fichiers de la section et les combine tous ensemble. Ensuite, j'utilise le minifier de YUI pour obtenir une version simplifiée du javascript. Parce que cela est servi par IIS, je préférerais activer la compression dans IIS pour obtenir la compression gzip. **** Ajoutée **** Mon script de déploiement est un script MSBuild. J'utilise également les excellentes tâches de la communauté MSBuild ( http://msbuildtasks.tigris.org/ ) pour aider à déployer une application.

Je ne publierai pas l'intégralité de mon fichier de script ici, mais voici quelques lignes pertinentes qui devraient montrer l'essentiel de ce qu'il fait.

La section suivante va exécuter le compilateur construit dans asp.net pour copier l'application sur le lecteur de destination. (Dans une étape précédente, je viens d'exécuter des commandes exec net use et de mapper un lecteur de partage réseau).

<Target Name="Precompile" DependsOnTargets="build;remoteconnect;GetTime">

        <MakeDir Directories="%(WebApplication.SharePath)\$(buildDate)" />

        <Message Text="Precompiling Website to %(WebApplication.SharePath)\$(buildDate)" />

        <AspNetCompiler
            VirtualPath="/%(WebApplication.VirtualDirectoryPath)"
            PhysicalPath="%(WebApplication.PhysicalPath)"
            TargetPath="%(WebApplication.SharePath)\$(buildDate)"
            Force="true"
            Updateable="true"
            Debug="$(Debug)"
            />
        <Message Text="copying the correct configuration files over" />

        <Exec Command="xcopy $(ConfigurationPath) %(WebApplication.SharePath)\$(buildDate) /S /E /Y" />

     </Target>

Une fois tous les projets de solution copiés, je lance ceci:

    <Target Name="_deploy">
        <Message Text="Removing Old Virtual Directory" />
        <WebDirectoryDelete
            VirtualDirectoryName="%(WebApplication.VirtualDirectoryPath)"
            ServerName="$(IISServer)"
            ContinueOnError="true"
            Username="$(username)"  
            HostHeaderName="$(HostHeader)"
            />

        <Message Text="Creating New Virtual Directory" />

        <WebDirectoryCreate 
            VirtualDirectoryName="%(WebApplication.VirtualDirectoryPath)" 
            VirtualDirectoryPhysicalPath="%(WebApplication.IISPath)\$(buildDate)"
            ServerName="$(IISServer)"
            EnableDefaultDoc="true"
            DefaultDoc="%(WebApplication.DefaultDocument)"
            Username="$(username)"
            HostHeaderName="$(HostHeader)"
            />
</Target>

Cela devrait suffire à vous aider à automatiser le déploiement. J'ai mis tout ça dans un fichier séparé appelé Aspnetdeploy.msbuild. Je viens de msbuild / t: Cible chaque fois que j'ai besoin de déployer dans un environnement.

Autres conseils

En réalité, il existe un moyen beaucoup plus simple d’utiliser Projets de déploiement Web (WDP). WDP gérera les complexités des outils aspnet__compiler et aspnet__merge . Vous pouvez personnaliser le processus en utilisant une interface utilisateur à l'intérieur de Visual Studio.

En ce qui concerne la compression des fichiers js, vous pouvez laisser tous vos fichiers js en place et les compresser uniquement pendant le processus de construction. Donc, dans le WDP, vous déclareriez quelque chose comme ceci:

<Project>
   REMOVE CONTENT HERE FOR WEB

<Import 
  Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<!-- Extend the build process -->
<PropertyGroup>
  <BuildDependsOn>
    $(BuildDependsOn);
    CompressJavascript
  </BuildDependsOn>
</PropertyGroup>

<Target Name="CompressJavascript">
  <ItemGroup>
    <_JSFilesToCompress Include="$(OutputPath)Scripts\**\*.js" />
  </ItemGroup>
  <Message Text="Compresing Javascript files" Importance="high" />
  <JSCompress Files="@(_JSFilesToCompress)" />
</Target>
</Project>

Ceci utilise la tâche JSCompress MSBuild des tâches de la communauté MSBuild qui, je pense, est basée sur JSMin.

L'idée est de laisser tous vos fichiers js tels qu'ils sont (c'est-à-dire debuggable / lisibles par l'homme) . Lorsque vous créez votre WDP, il copie d'abord les fichiers js dans OutputPath , puis la cible CompressJavascript est appelée pour réduire les fichiers js. Cela ne modifie pas vos fichiers source originaux, mais seulement ceux du dossier de sortie du projet WDP. Ensuite, vous déployez les fichiers dans le chemin de sortie WDP, qui inclut le site précompilé. J'ai couvert ce scénario dans mon livre (lien sous mon nom) .

Vous pouvez également laisser WDP gérer la création du répertoire virtuel. Il vous suffit de cocher une case et de renseigner le nom du répertoire virtuel.

Pour certains liens sur MSBuild:

Sayed Ibrahim Hashimi

Mon livre: À l'intérieur du moteur de construction Microsoft: utilisation de MSBuild et de Team Foundation Build

Scott Hanselman a récemment écrit un blog sur la combinaison et déplacement de scripts vers des fichiers statiques , en utilisant en principe ScriptManager avec des références CompositeScript et un attribut Path :

<asp:ScriptManager runat="server">
    <CompositeScript path="http://www.example.com/1.js">
        <Scripts>
            <asp:ScriptReference />
            <asp:ScriptReference />
            <!-- etc. -->
        </Scripts>
    </CompositeScript>
</asp:ScriptManager>

En termes de réduction des fichiers statiques, vous devez (et devez) utiliser des outils de réduction au moment de la génération / du déploiement.

MvcContrib.IncludeHandling convient bien à cette situation. Dans l'exemple, j'ai un modèle avec une collection de styles (chaîne). Aussi, si j'ai besoin d'ajouter un Style / JS personnalisé à la page, je peux le faire aussi. Ensuite, appeler Html.RenderCss combine tous les styles / js dans un seul fichier et le réduit.

<head>
<% foreach (var styleSheet in Model.Styles) {%>
<% Html.IncludeCss(styleSheet)); 

<% } %>
<% Html.IncludeCss("~/Scripts/jquery.1.4.2.js")); 

<%= Html.RenderCss() %>
</head>

Même méthode pour javascript.

<%
Html.IncludeJs("~/scripts/ConsoleLogger.js");
Html.IncludeJs("~/scripts/jquery.log.js");
Html.IncludeJs("~/Scripts/2010.1.416/jquery.validate.min.js");
Html.IncludeJs("~/Scripts/2010.1.416/telerik.calendar.min.js");
Html.IncludeJs("~/Scripts/2010.1.416/telerik.datepicker.js");
Html.IncludeJs("~/scripts/jquery.ui.datepicker-en-GB.js");
%>
   

Lorsque ceci est rendu au client, le résultat est le suivant (fichier 1 combiné minifié)

<link rel='stylesheet' type='text/css' href='/include/css/-QdUg9EnX5mpI0e4aKAaOySIbno%40'/>

L’API offre également un indicateur de débogage qui, lorsqu'il est activé, ne réduit pas ni ne combine les scripts lorsqu’il est défini, ce qui est très utile.

En quelques minutes, je suis passé de la note de Yslow de F à B. (24 scripts au lieu de 2) ... Génial! Et une goutte de 40kbs.

Inconvénient évident: le serveur effectue la compression à la volée. Je pense qu'il existe des options pour mettre en cache le script combiné pendant une période définie, ce qui permettrait de remédier rapidement à ce problème.

Comme d'autres l'ont suggéré, vous feriez mieux de créer une version statique réduite. Sinon, une version de YUICompressor est disponible pour .NET ici: http://www.codeplex.com/YUICompressor

Vous pouvez utiliser MvcContrib.IncludeHandling. Il:

  • Prend en charge CSS et JS
  • Combine une seule demande
  • Minifie
  • Compresses Gzip / Deflate
  • Configure les en-têtes de cache
  • Utilise les méthodes d'extension HTMLHelper pour enregistrer les inclus, puis les combiner au moment de l'exécution
  • est connectable via IoC

Sous les couvertures, il utilise YUICompressor.

J'ai écrit quelque chose pour gérer cela automatiquement pour moi. Il utilise le compilateur de fermeture de Google. Vous pouvez lire le code ici:

http://www.picnet.com.au/blogs/Guido/post/2009/12/10/Javascript-runtime-compilation-using-AspNet-and-Googles-Closure-Compiler .aspx

Merci

Guido

Je sais que c’est une vieille question, mais c’est la première fois que j’étais en train de faire des recherches de minification. Je recommanderais d'utiliser Gruntjs, http://gruntjs.com . C’est un outil de construction Web complet.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top