Domanda

Quindi ho un'app ASP.NET MVC che fa riferimento a una serie di file javascript in vari punti (nel master del sito e riferimenti aggiuntivi anche in diverse viste).

Mi piacerebbe sapere se esiste un modo automatizzato per comprimere e minimizzare tali riferimenti in un singolo file .js ove possibile. Tale che questo ...

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

... potrebbe essere ridotto a qualcosa del genere ...

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

Grazie

È stato utile?

Soluzione

Personalmente penso che mantenere i file separati durante lo sviluppo sia inestimabile e che durante la produzione è quando qualcosa di simile conta. Quindi ho modificato il mio script di distribuzione per farlo sopra.

Ho una sezione che dice:

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

E nel mio file della pagina principale utilizzo:

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>
<% } %>

Lo script di compilazione prende tutti i file nella sezione e li combina tutti insieme. Quindi uso il minificatore di YUI per ottenere una versione ridotta di JavaScript. Poiché questo è servito da IIS, preferirei attivare la compressione in IIS per ottenere la compressione gzip. **** Aggiunto **** Il mio script di distribuzione è uno script MSBuild. Uso anche le eccellenti attività della community di MSBuild ( http://msbuildtasks.tigris.org/ ) per aiutare a distribuire un applicazione.

Non pubblicherò qui il mio intero file di script, ma qui ci sono alcune righe pertinenti per dimostrare la maggior parte di ciò che fa.

La seguente sezione eseguirà il compilatore build in asp.net per copiare l'applicazione sull'unità di destinazione. (In un passaggio precedente ho appena eseguito i comandi exec net use e mappato un'unità di condivisione di rete).

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

Dopo aver copiato tutti i progetti della soluzione, eseguo questo:

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

Dovrebbe essere sufficiente per iniziare a automatizzare la distribuzione. Ho messo tutte queste cose in un file separato chiamato Aspnetdeploy.msbuild. Ho appena msbuild / t: target ogni volta che ho bisogno di distribuire in un ambiente.

Altri suggerimenti

In realtà c'è un modo molto più semplice usando Progetti di distribuzione Web (WDP). Il WDP gestirà le complessità dello strumento aspnet__compiler e aspnet__merge . Puoi personalizzare il processo tramite un'interfaccia utente all'interno di Visual Studio.

Per quanto riguarda la compressione dei file js, puoi lasciare tutti i tuoi file js in posizione e comprimere questi file durante il processo di compilazione. Quindi nel WDP dichiareresti qualcosa del genere:

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

Questo utilizza l'attività JSCompress MSBuild dalle Attività della community MSBuild che ritengo sia basata su JSMin.

L'idea è di lasciare tutti i file js così come sono (ovvero debuggable / leggibili dall'uomo) . Quando crei il tuo WDP, prima copia i file js in OutputPath e quindi viene chiamato il target CompressJavascript per ridurre al minimo i file js. Ciò non modifica i file di origine originali, ma solo quelli nella cartella di output del progetto WDP. Quindi si distribuiscono i file nel percorso di output di WDP, che include il sito precompilato. Ho trattato questo esatto scenario nel mio libro (link sotto il mio nome) .

Puoi anche lasciare che WDP gestisca anche la creazione della Directory virtuale, seleziona una casella di controllo e inserisci il nome della directory virtuale.

Per alcuni link su MSBuild:

Detto Ibrahim Hashimi

Il mio libro: All'interno di Microsoft Build Engine: utilizzo di MSBuild e Team Foundation Build

Scott Hanselman ha recentemente pubblicato un blog su combinando e spostando gli script in file statici , fondamentalmente usando il ScriptManager con riferimenti CompositeScript e un attributo Path :

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

In termini di minimizzazione dei file statici, probabilmente dovrai (e dovresti) usare gli strumenti di minimizzazione in fase di compilazione / distribuzione.

MvcContrib.IncludeHandling funziona bene per questa situazione. Nell'esempio, ho un modello con una raccolta di stili (stringa). Inoltre, se devo aggiungere uno Style / JS personalizzato alla pagina, allora posso farlo. Quindi chiamare Html.RenderCss combina tutti gli stili / j in un unico file e lo minimizza.

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

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

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

Allo stesso modo per 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");
%>
   

Quando questo viene reso al client l'output appare così (file combinato combinato 1)

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

L'API offre anche un flag di debug che quando attivato non minimizza o combina gli script quando impostati, il che è molto utile.

In pochi minuti sono passato dal punteggio Yslow di F a B. (24 script fino a 2) ... Fantastico! E una goccia di 40kbs.

Il lato negativo evidente è che il server sta eseguendo la compressione al volo. Penso che ci siano opzioni per memorizzare nella cache lo script combinato per un periodo definito, ma ciò allevierebbe rapidamente questo.

Come altri hanno suggerito, sarebbe meglio creare una build minimizzata statica. In alternativa, è disponibile una versione di YUICompressor per .NET qui: http://www.codeplex.com/YUICompressor

Puoi usare MvcContrib.IncludeHandling. E:

  • Supporta CSS e JS
  • Combina in un'unica richiesta
  • Minifies
  • Comprime Gzip / Deflate
  • Imposta le intestazioni della cache
  • Utilizza i metodi di estensione HTMLHelper per registrare le inclusioni per poi combinarle in fase di esecuzione
  • È collegabile tramite IoC

Sotto le coperte, utilizza YUICompressor.

Ho scritto qualcosa per gestirlo automaticamente. Utilizza il compilatore di chiusura di Google. Puoi leggere il codice qui:

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

Grazie

Guido

So che questa è una vecchia domanda, ma è emersa prima mentre stavo facendo alcune ricerche di minificazione. Consiglierei di utilizzare Gruntjs, http://gruntjs.com . È uno strumento di compilazione web completo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top