Nasze ostatnie projekty

Wątorówka

Kontakt Z nami

DZIAŁ TECHNICZNY

hosting, domeny, kontakt z administratorem

Bartosz Radwan
mobile: +48 512 044 262
e-mail: b.radwan@znaminet.pl

DESIGN

projekty stron, grafika, animacje flash

Marzena Radwan
mobile: +48 500 145 203
e-mail: m.radwan@znaminet.pl

Własny build MooTools, optymalizacja JavaScript

2009.05.08 Źródło: Informacje własne

Jeżeli używasz frameworków JavaScript, to pewnie dobrze wiesz, że stanowią one czasami objetościowo dużą cześć Twojego serwisu. Opłaca się zatem korzystać jedynie z tych komponentów, które sa nam potrzebne. MooTools oraz komponenty Clientcide doskonale nam to ułatwiają, w tym artykule pokażemy jak przygotować własny build.

 

Wstęp

Na poczatek kilka przydatnych linków, które pozwolą nam zorientować się co to są te frameworki, jakie problemy rodzi stosowanie dużych ilości JavaScriptu, oraz co możemy z tym robić. Następnie opiszemy jak zbudować swoją własną wersję MooTools komponentów Clientcide. Na koniec opiszemy po krótce co zrobić z naszym kodem JavaScript, żeby było w miarę dobrze, szczegółowe informacje na ten temat znajdziecie w prezentacji o YSlow.

Linki

Własny build Clientcide wraz z zależnościami MooTools.core, MooTools.more

Musimy zaopatrzyć się w źródła MooTools.{core, more} oraz Clientcide, są one dostępne przez gita w repozytorium Aarona Newtona, wykonujemy po kolei kroki:

Pobieramy komponenty Clientcide:

[bociek@pldmachine cnet]$ git clone git://github.com/anutron/clientcide.git
Initialized empty Git repository in /home/users/bociek/cnet/clientcide/.git/
remote: Counting objects: 1120, done.
remote: Compressing objects: 100% (892/892), done.
remote: Total 1120 (delta 441), reused 725 (delta 190)
Receiving objects: 100% (1120/1120), 1.73 MiB | 44 KiB/s, done.
Resolving deltas: 100% (441/441), done.
[bociek@pldmachine cnet]$

W podobny sposób pobieramy MooTools.core i MooTools.more:
Pamiętamy jednak, by tym razem podać nazwy katalogów, do których pobierzemy źródła  core i more - takie lokalizacje są wymagane przez clientcide.

[bociek@pldmachine cnet]$ git clone git://github.com/anutron/mootools-core.git core
[bociek@pldmachine cnet]$ git://github.com/anutron/mootools-more.git more

Przygotowanie środowiska do budowania:
Po poprawnym zakończeniu tych operacji  w katalogu, w którym je przeprowadzaliśmy powinny być katalogi clientcide, core, more. Będziemy budować komponenty Clientcide, wiec przechodzimy do katalogu clientcide, tam znajdziemy skrypt  ruby build.rb służący do zbudowania własnego zestawu komponentów. Skrypt build.js wymaga pewnych komponentów ryby'ego, w moim przypadku (Linux PLD 3.0 Th), sprawę załatwiłem instalując najpierw pakiety ruby-RubyGems-1.2.0-1.i686 oraz ruby-devel-1.8.7.72-6.i686 wraz z zależnościami, a następnie przy pomocy gema pakiet json, który konieczny jest do rozwiązywania zależności pomiędzy komponentami zapisanymi w formacie JSON.
Aby zainstalować potrzebny pakiet json po prosty wykonujemy polecenie:

[root@pldmachine ~]# gem install json

Teraz możemy już przystąpić do właściwego budowania.

Przygotowanie własnego pełnego i okrojonego buildu

Skrypt build.rb odpalony bez parametrów zbuduje nam pełen zestaw. Spróbujmy to zrobić.
[bociek@pldmachine clientcide]$ ./build.rb
[...]
MooTools Built './built.js'
Included Scripts:
Core Browser Selectors Element Array String Function Number Hash DomReady Element.Event Event Cookie Class Class.Extras Swiff JSON Fx.Transitions Fx Fx.Tween Fx.CSS Element.Style Fx.Morph Request.JSON Request Request.HTML Element.Dimensions Drag.Move More Drag Slider Class.Binds Sortables Lang Log IframeShim Element.Position Element.Measure Class.Occlude Group Color Assets Hash.Cookie Date.English.US FormValidator.English Tips Scroller Chain.Wait Class.Refactor URI String.Extras Hash.Extras Date.Extras Date Array.Extras URI.Relative String.QueryString Fx.SmoothScroll Fx.Scroll Fx.Slide Fx.Accordion Fx.Elements Fx.Move Fx.Sort Fx.Reveal Element.Shortcuts Request.JSONP Request.Periodical Request.Queue FormValidator.Extras FormValidator Element.Forms FormValidator.Inline OverText Element.Pin dbug Clientcide Collapsable TabSwapper MenuSlider HoverGroup DollarG SimpleSlideShow Class.ToElement SimpleCarousel MultipleOpenAccordion MooScroller HtmlTable DollarE SimpleEditor.French SimpleEditor.Dutch SimpleEditor.English.US SimpleEditor.Portuguese SimpleEditor.Spanish Autocompleter.Local Autocompleter Autocompleter.Observer Autocompleter.Clientcide Autocompleter.Remote Autocompleter.JSONP Lightbox Modalizer PostEditor.Forum PostEditor Element.Delegation Fx.Marquee SimpleEditor FormValidator.Tips StickyWin.PointyTip StickyWin.UI.Pointy StickyWin.UI StickyWin StyleWriter InputFocus TagMaker Fupdate.Append Fupdate Waiter Confirmer ProductPicker Fupdate.Prompt StickyWin.Modal StickyWin.Ajax DatePicker DatePicker.Extras PopupDetails ObjectBrowser IconMenu StickyWin.alert StickyWin.Drag StickyWin.Fx Tips.Pointy Request.Queue.Compat Date.Compat Element.Shortcuts.Compat OverText.Compat Element.MouseOvers.Compat Browser.Extras.Compat JsonP.Compat String.Extras.Compat IframeShim.Compat Element.Position.Compat Element.Forms.Compat FixPNG Popup
[bociek@pldmachine clientcide]$

Sprawdźmy, ile waży nasz build:

-rw-r--r-- 1 bociek users 467K maj 1 14:01 built.js

Krótko mówiąc... masakra... To jest nie do przyjęcia... przecież na swojej stronie wykorzystujemy tylko MultiOpenAccordion... no to zbudujmy tylko to, co jest potrzebne:

[bociek@pldmachine clientcide]$ ./build.rb MultipleOpenAccordion
[...]
MooTools Built './built.js'
Included Scripts:
MultipleOpenAccordion Element.Event Element Browser Core Array String Function Number Hash Event Fx.Reveal More Fx.Morph Fx.CSS Fx Class.Extras Class Element.Style Element.Shortcuts Element.Measure

No... i ciekawe ile waży:

-rw-r--r-- 1 bociek users 78K maj 1 14:23 built.js

Jest znacznie lepiej... A teraz dorzućmy kilka komponentów:

[bociek@pldmachine clientcide]$ ./build.rb MultipleOpenAccordion Fupdate Lightbox
MooTools Built './built.js'
Included Scripts:
MultipleOpenAccordion Element.Event Element Browser Core Array String Function Number Hash Event Fx.Reveal More Fx.Morph Fx.CSS Fx Class.Extras Class Element.Style Element.Shortcuts Element.Measure Fupdate Request.HTML Request Class.ToElement Clientcide Class.Occlude Waiter Fx.Elements Class.Refactor Element.Position Element.Dimensions IframeShim String.QueryString Lightbox Selectors Fx.Tween DomReady Class.Binds Modalizer
[bociek@pldmachine clientcide]$

Prawie 2 razu więcej, komponentów również:

-rw-r--r-- 1 bociek users 140K maj 1 14:27 built.js

Dużo lepiej, ale nadal nie idealnie... ale jak się zaraz przekonamy, są jeszcze dwie rzeczy, jakie możemy teraz zrobić. W efekcie prześlemy "tylko" kilkadziesiąt kB danych

Dyskusja o okrojeniu komponentów i kompresji.

Efektem naszego budowania jest 140kB pliku js, który jest ładnie sformatowany, human-readable. Jest to dobry czas, żeby w imię optymalizacji dopisać na końcu swój kod korzystający z komponentów i go przetestować. Załóżmy, że mamy już ten krok za sobą, mamy około 140kB kodu w jednym pliku, który zawiera JavaScript dla całej naszej witryny. W ten sposób klient będzie musiał pobrać go tylko 1 raz. To jest dobre.

Kompresja etap pierwszy

Jak zauważyliśmy na początku kod jest ładnie sformatowany, zawiera komentarze... hm.. zaraz zaraz.. przecież przeglądarka nie potrzebuje tych wszystkich tabów, spacji i komentarzy do poprawnego działania... można by je usunąć, no ale ręcznie... nie ma mowy. Są do tego narzędzia, jak np. JSMin. Ja osobiście korzystam z wersji pythonowej.  No to przepuśćmy nasz skrypt przez to narzędzie:

[bociek@pldmachine clientcide]$ cat built.js | ./jsmin.py > build_jsmin.js
[bociek@pldmachine clientcide]$ ls -alh build_jsmin.js
-rw-r--r-- 1 bociek users 109K maj 1 14:38 build_jsmin.js
[bociek@pldmachine clientcide]$

Już lepiej... ale to nie jest jeszcze wszystko, co możemy zrobić.

Kompresja etap drugi

Drugi etap kompresji, to kompresja w locie dokonywana przez serwer http, i mod_deflate. Jeżeli nie masz wpływu na konfigurację serwera, to może sie okazać, że nie jesteś w stanie tego przeprowadzić. W moim wypadku ograniczało się to do zainstalowania pakietu apache-mod_deflate-2.2.11-4.i686 oraz dodania w konfigu serwera apache takiej linijki:

AddOutputFilterByType DEFLATE application/x-httpd-php
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/javascript application/x-javascript

No to Sprawdźmy efekty
Na dysku serwera:

-rw-r--r-- 1 bociek users 109K maj 1 14:48 /home/users/bociek/stuff/build_jsmin.js

W logach serwera www:

mydomain.info ddd.ddd.237.134 - - [01/May/2009:14:48:58 +0200] "GET /tmp/build_jsmin.js HTTP/1.1" 200 29951 "http://mydomain.info/tmp/" "Opera/9.63 (X11; Linux i686; U; PLD/3.0 (Th); en) Presto/2.1.1"

Tym razem przetransferowaliśmy tylko 30kB danych. Zwarzywszy na to, że nawet przy takim zestawie efektów jesteśmy w stanie bardzo ożywić naszą stronę (byle by nie przesadzać), efekt nie jest zły. Weźmy też pod uwagę, że jeżeli w skrypcie zawarliśmy kod który jest wykorzystywany na wszystkich naszych stronach, to klient potrzebuje pobrać tylko raz ten plik.

Podsumowanie

W dzisiejszych czasach strony internetowe często żyją własnym życiem - w sensie, że coś sie rusza, sporo technologii ajaxowych się wykorzystuje, czasami aż tego za dużo, nie mówiąc o problemach z indeksowaniem takich stron... No ale jeżeli wykorzystujemy te rzeczy z umiarem i przede wszystkim świadomością konsekwencji, to wszystko w porządku. Przy dzisiejszych przepustowościach łącz te 30kB nie jest takie straszne jak kilka lat temu. Wydajność serwerów także często nie jest problemem, także na kompresję w locie możemy sobie zazwyczaj pozwolić, no a jeżeli doświadczamy z tego powodu problemów wydajnościowych, to zawsze można te rzeczy trzymać w cache i serwować z niego... ale to już temat na zupełnie inną opowieść.

Widzieliśmy, co można zrobić po kolei, żeby zejść z rozmiarem ilością plików JavaScript, ale zbierzmy to wszystko razem:

  1. Ilość plików .js ma znaczenie - ze względu na to, w jaki sposób przeglądarki je pobierają stosuj jak najmniej plików (szczegóły w prezentacji).
  2. Stosując frameworki o ile to możliwe zawieraj tylko te komponenty, których używasz. Dużo na tym oszczędzisz
  3. Przeglądarka nie potrzebuje sformatowanego kodu - zmniejsz kod przy użyciu jednego z dostępnych narzędzi
  4. Nawet zmniejszony kod, to nadal czysty tekst, więc raczej dobrze będzie się poddawał kompresji. Wykorzystaj to.
  5. Obserwuj rezultaty działań i ich konsekwencje - wnioski wprowadzaj w życie, słowem - myśl.