[컴][웹] GWT 사용하기 - Bundles




ClientBundle

여러가지 resources 들(image, css, js 등) 을 web browser 가 download 받는 것은 일이 많다. 그래서 이것을 하나로 묶어서 다운로드 할 수 있도록 해주는 녀석이 Bundle 이다.


resource 전달 최적화


load time 에 영향을 미치는 요소

  • connection count
  • total bytes

connection count 를 줄이려고 하는 것인데 이를 위해서 합칠수 있는 것들은 합친다.(resource embedding)
total bytes 를 줄이기 위해서 먼저 비슷한 녀석끼리 묶고 압축한다. 그리고 나서 이런 녀석들을 다시 모아서 묶게 된다.
ImageResource 로 사용되는 Image 들은 하나의 image 로 합쳐지는데, 이런 것이 total byte 도 줄일수 있고, connection count 도 줄이는 방법이 된다.

loading time 을 줄이는 다른 방법, cache
특정 파일을 cache 할 수 있다.
browser 가 특정 file 을 cache 하도록 한다.(cache.xxx 의 확장자(extension) 을 가진 녀석들)

이런 원리를 사용해서 ClientBundle 은 loading time 을 줄이게 된다.



DataResource 라는 resource type 을 이용해서 임의의 file type 을 bundle 할 수 있다. 즉 DataResource 는 icon 이 될 수도 있고 pdf, or zip 등처럼 다양한 녀석이 될 수 있다.



DataResource 에 대한 caching 을 제공하기 위해 다음 2가지 방법중 한가지를 사용한다.
file 을 module's output directory 에 copy 하는것
이 때 filename 은 다른 GWT cacheable 파일들 처럼 hash 값으로 만들게 된다.
ex)4351535164.cache.jpg

두번째 방법은 작은 파일에만 사용된다. byte 를 Base64 형태로 바꿔서 data 처럼 보이는 URL 로 만든다. 그리고 이 녀석을 module 의 JavaScript payload 안에 넣는다. 이 녀석이 총 byte 를 약 1/3 정도 증가시키게 된다. 하지만 connection count 를 줄이는 효과를 가질 수 있다.

이 두번째 방법을 사용하고 싶지 않은 경우에는 아래처럼 설정 해 줄 수 있다. module.xml 에 아래와 같이 설정하면 module 에서 전혀 이 두번째 방법이 사용되지 않는다.
<set-property name="ClientBundle.enableInlining"
value="false"/>

이런 경우말고 개별적으로 이런 방법을 쓰고 싶지 않은 경우에는
DataResource 는 @DoNotEmbed annotation 을 제공한다.
DataResource 의 accesor method(getter or setter) 에 이 녀석을 사용하면 된다.


첫번째 방법에서 cache 의 이름을 hash 값으로 사용하지 않을 수도 있다. 아래와 같은 방법을 사용하면 된다. 이 방법은 debugging 에 유용하다.
<set-configuration-property name="ClientBundle.enableRenaming "value="false"/>

set-configuration-property 는 configuration property 를 설정할 때 쓰이고,
set-property 는 deferred binding property 를 정할 때 쓰인다.





public interface DataResources extends ClientBundle {
  DataResources IMPL = 
    (DataResources) GWT.create(DataResources.class);

  @Source("BigPhoto.jpg")
  DataResource bigPhoto();

  @DoNotEmbed
  @Source("Document.pdf")
  DataResource document();

  @MimeType("image/png")
  @Source("slashdot.png")
  DataResource slashdot();
}

Source 가 생략되는 경우도 있는데, 확장자가 기본확장자이고, filename 과 method name 이 일치하는 경우다. 기본 확장자는 아래와 같다. 이외의 경우에는 @Source 를 적어줘야 하며, 생략할 수 있는 경우에도 @Source 를 적어도 괜찮으니, 그냥 무조건 적는다고 여기면 될 듯 하다.

  • TextResource, ExternalTextResource: .txt
  • ImageResource : .png, .jpg, .gif, .bmp (이 순서대로 찾는다. png 가 우선수위가 높다.)
  • CssResource :.css


이 ClientBundle 을 위 처럼 직접작성해도 되고 eclipse plugin 으로 제공하는 tool 을 이용할 수도 있다.





TextResource

ExternalTextResource

TextResource 는 JavaScript payload 에 넣어서 최적화 한다. DataResource 에서와 같이
module.xml 에
  • <extend-property name='locale' values='es' />
추가하는 방법으로 자동으로 internationalized 된다.
  • Resources.IMPL.textName().getText()
에서 getText() 에서 알아서 나라에 알맞는 text 를 return 해 준다.

UiBinder 에서는 아래 처럼 사용할 수 있다.
  • <g:Label text="{res.text.getText}" />
ExternalTextResource 는 javascript payload 안으로 들어가지는 않고, compile time 에 이 ExternalTextResource들을 하나로 모아서 하나의 file 을 만들게 된다. 그리고 이 bundle 안에 있는 ExternalTextResource 중 한녀석이 사용되어 질 때 download 를 하게 된다. 그렇기 때문에 download 가 잘 되었는지 여부에 따른 행동을 결정해 주게 된다. 이것을 ResourceCallback 을 통해 하게 된다.

아래 code 에 onSuccess 부분은 resource 를 잘 가져왔는지 여부에 대한 error 는 try~catch 부분에서 처리가 되며, 잘 가져온 이후에 GWT 에서 parsing 을 못하는 등의 문제는 onError 에서 처리하게 된다.


 try {
  res.extText().getText(new ResourceCallback() {
    public void onSuccess(TextResource resource) {
      etextLabel.setText(resource.getText());
    }
    public void onError(ResourceException e) {
      Window.alert("Failed to retrieve ExternalTextResource:\n"
          + e.getMessage());
    }
  });

} catch (ResourceException e) {
  Window.alert("Failed to retrieve ExternalTextResource:\n"
      + e.getMessage());
}

이 ExternalTextResource 를 다운로드 받게 되면 녀석들을 memory 에 놓고, 거기서 필요한 부분만 가져오게 된다.


ImageResource

이 녀석은 위에서 얘기한 delivery time 을 줄이기 위한 2 가지 방식에 더해 image stripe file 을 이용한다.

어떤 녀석을 어떤 방법으로 전달할 것인가는 GWT 가 compile time 에 정하게 된다.

ImageResource 또한 localization 을 제공하는데, 대표적인 것이 RTL (right to left) 에 대한 지원이다. 이것은
@ImageOptions(flipRtl = true)
을 하면 된다. 그러면 이미지가 mirroring 되게 된다. 이 옵션이 있으면 GWT 가 compile time 에 image 를 right-to-left 용으로 만들어주게 된다.


GWT 는 2개의 ClientBundleGenerator 를 가지고 있다.

  1. InlineClientBundleGenerator
  2. StaticClientBundleGenerator


<generate-with
  class="com.google.gwt.resources.rebind.context.StaticClientBundleGenerator">
  <when-type-assignable
    class="com.manning.gwtia.ch05.client.imageresource.StaticClientBundle" />
</generate-with>

위와같이 설정해 놓으면, StaticClientBundle 을 extends 한 Resource는 compiler 가 compile 할 때 자기 마음대로 Generator 를 결정하지 않고 위에 적힌 지시를 따르게 된다. 즉 StaticClientBundleGenerator 를 이용하게 된다.

개별적으로 inline 을 막는 방법


  • @ImageOptions(preventInlining=true) 

을 이용하면 개별적으로 inlining 이 되는 것을 막을 수 있다. 이녀석도 accessor 에 사용하면 된다. 이녀석은 다른 ImageResource 와 bundle 하는 것도 막기 때문에 이녀석은 큰 size 의 자주 사용되지 않는 녀석에 쓰는 것이 낫다.


CssResource

css 도 optimization 을 해준다. 빈 class name 을 없애고, merge 가 가능한 녀석들을 merge 하고, comment 를 없애고, space 를 없애고, 그리고 obfuscation 을 해준다. 이때 obfuscation 때문에 GWT 에서 직접적으로 class 이름을 사용할 수는 없다. 아래와 같은 방법을 통해서 사용해야 한다.


public interface Resources extends ClientBundle {

    Resources IMPL = GWT.create(Resources.class);

    @Source("standard.css")
    Stdcss stdcss();
    ...



public interface Stdcss extends CssResource {

    @ClassName("gwt-ToggleButton-up-disabled")
    String gwtToggleButtonUpDisabled();
    ...


기존의 code 에서도 사용하는 css 라고 한다면 obfuscation 을 하면 안된다. 이런 경웨 css file 내부에 @external 을 사용해서 CssResource 에서 제외시킬 수 있다.

  • @external two, three /* two, three 는 이름이 변경되지 않는다. */

파일전체에 @external 을 사용하는 경우라면 아래와 같이 사용하면 된다.

@Source("main.css")
@CssResource.NotStrict 
MyCss css();


@def

contants cssResource 를 사용하면 .css 내부에서 constants 를 사용할 수 있다. 이 constants 는 css 내부에서도 사용할 수 있고, GWT java code 내에서도 사용할 수 있다.

constants 는 아래처럼 정의할 수 있다. 여기에 value() 를 사용할 수 있는데, 이부분은 여기를 참고하자.

@def BORDER_WIDTH 10px;
.box{
  border: BORDER_WIDTH solid black;
}


public interface Basic extends CssResource {
  String BORDER_WIDTH(); 
  String box(); 
}

@def SPRITE_WIDTH value('imageResource.getWidth', 'px');


@eval

@eval 이 있다.
이녀석은 @def 와 같은 방법으로 사용할 수 있다. 단 @eval 은 CssResource 를 이용해서 사용할 수 없다.(accessor 를 가질 수 없다.)
@eval 을 이용하면 stylesheet 이 inject 될 때 static class method 로부터 값을 얻어올 수 있다.






References

  1. https://code.google.com/p/google-web-toolkit/w/list, GWT google code page



댓글 없음:

댓글 쓰기