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' />
- Resources.IMPL.textName().getText()
UiBinder 에서는 아래 처럼 사용할 수 있다.
- <g:Label text="{res.text.getText}" />
아래 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 를 가지고 있다.
- InlineClientBundleGenerator
- 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
- https://code.google.com/p/google-web-toolkit/w/list, GWT google code page
댓글 없음:
댓글 쓰기