polymer따라잡기
TRANSCRIPT
POLYMER ?• https://www.polymer-project.org/
• 사전적인 의미 : 중합체, 고분자
• 2013.07.11 Pre-release( stable version ) 현재 0.5.2 ( 2015.01.14 기준)
• 2014년 Google 이 공개한 새로운 타입의 Web을 위한 라이브러리 (?)( webcomponents를 만드는.. )
• HTML을 확장해서 재사용이 가능한 custom element 제공
• JS 라이브러리들 안에서만 이용 가능했던 확장성과 캡슐화를 제공
• Shadow Dom, Custom Elements, 모델 기반 view를 포함한 최신 기술 적용
• 빠르고 쉽게 web 어플리케이션 제작 가능
• 현재 최신 browser에서 native 로 polymer features 채택중
• 라이센스 : BSD License
WEBCOMPONENTS?• 쉽고 안정적으로 재사용 할 수 있는 위젯을 만들기 위해 HTML/CSS/JS 지식을 활용 할수 있도록 하는 사양의 집합
• 다시 말하면, 웹 문서 및 어플리케이션 안에서 재사용 가능한 위젯을 만들기 위한것 !
• 각 HTML elements 안에서 encapsulation & interoperability 가능하게 하는것
• 내부 구현 때문에 Component가 다음 버전으로 바뀌어도 Page는 변경 할 필요가 없다.
• http://www.w3.org/wiki/WebComponents/
• 현재 W3C에서 표준화가 진행중
• WebApps -> WebComponents 로 변경
• Chromium 프로젝트에서 blink 에 구현중 http://www.chromium.org/blink/web-components
• Mozilla 는 Brick! : http://brick.mozilla.io/ , http://mozbrick.github.io/brick-tabbar/
✴ 즉 Polymer 가 Web Components(?) Polymer는 Web Components를 구현 하기 위한 도구 (google 개발자가 주도?)
WEBCOMPONENTS MAIN ELEMENTS-1
• WebComponents 를 지탱하는 메인 요소 4개
• Custom Elements
• http://w3c.github.io/webcomponents/spec/custom/
• 사용자에 의해 정의된 Element
• Shadow DOM
• vs Composed DOM ( Rendered DOM) : 렌더링을 안해도 됨
• http://w3c.github.io/webcomponents/spec/custom/,
• http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/
• Document Tree 에 Shadow Host 가 존재 하며 해당 host 가 shadow dom의 root
• Presentation에서 content를 분리 목적
WEBCOMPONENTS MAIN ELEMENTS-2
• HTML Imports
• http://w3c.github.io/webcomponents/spec/imports/
• HTML 문서를 외부자원 처럼 링크 하는 것
• link 요소의 “import” 타입 사용
• ex: < link rel=“import” href=“/imports/newHTML.html”>
• HTML Template
• https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html
• <template> Element : document fragment ( Document 안에 없다는 의미 )
• 사용자가 활성화하기 전까지는 마크업 안에서 비활성화
• JS 를 안에 저장 시킬수는 있지만, 필요할때까지 실행하지 않음
CUSTOM ELEMENTS• 사용자에 의해 직접 정의 될수 있음
• ex: ) HTML :
• ex: ) JS :
• 표준 DOM 메소드로 만들수 있으며, 이벤트를 붙히거나, 프로퍼티에 접근 하거나, CSS 를 입히는것도 가능
• document.registerElement를 이용해서 사용도 가능
<kazikai-element></kazikai-element>
var kazikaiEl = document.createElement( “kazikai-element” );kazikaiEl.innerHTML = “Hello world kazikai”;
var kazikaiElement = document.registerElement( “kazikai-element” );var kazikaiEl = new kazikaiElement();
SHADOW DOM• 목적은 컨텐츠와 프리젠테이션 영역을 분리 ( Polymer 에서는 <template> 태그 안에 있는 부분이 shadow dom)
• shadow dom 은 3개의 서브 트리로 표현 가능
• light DOM:
• custom element를 이용해서 만든 dom
• 사용자에게는 DOM에서 일반적인 서브트리로 보여짐
• shadow DOM ( by document-fragment )
• custom element가 정의되어 shadow root 에 붙혀진 DOM
• 숨겨져 있으며 custom element 의 자식 노드가 아니다.
• composed DOM ( = light DOM + shadow DOM )
• 렌더링 된 DOM, 브라우저에서 실제로 보여지는 부분
HTML IMPORTS• 다른 HTML 문서에서 HTML문서를 재활용 하는 방법
• <script> 태그처럼 외부에서 불러와서 활용
• <link rel =“import” href=“my-custom-element.html”>
• Feature detection 방법 : chrome 31+, 36+에서 최신 스펙 적용 or Polyfill사용
• Load / Error 에 이벤트 걸기
function supportsImports() { return 'import' in document.createElement('link');}if (supportsImports()) { // Good to go!} else { // Use other libraries/require systems to load files.}
<script async> function handleLoad(e) { console.log('Loaded import: ' + e.target.href); } function handleError(e) { console.log('Error loading import: ' + e.target.href); }</script><link rel="import" href=“file.html" onload="handleLoad(event)" onerror="handleError(event)">
TEMPLATES• http://webcomponents.org/articles/introduction-to-template-element/
• https://html.spec.whatwg.org/multipage/scripting.html#the-template-element
• PHP, Django, Ruby on Rails 등등 서버기반 기술에서 주로 사용
• 클라이언트 기반 에서는 주로 mustach.js, handlebars.js, angular.js, backbone.js 등 이 있음
• tempalte을 구동안 정의했던 방식
• div 방식: <div sytle=“display:none”><div>
• script방식 <scritp type=“text/x-handlebars-template></script>
• 결국 렌더링 되지 않고 js/css 를 포함 할수있는 HTML 요소 기반의 template을 만들자
• 그래서 만들어짐
• <tempalte></template>
WEBCOMPONENTS POLYFILL
• 현존 하는 브라우저중에는 해당 Spec 을 지원하는 브라우저가 거의 없음
• Polyfill을 사용해서 해결 가능 하다. webcomponents.js ( http://webcomponents.org/ )
• $ bower install --save webcomponentsjs
• 원래 이름은 platform.js -> webcomponents.js
• https://blog.polymer-project.org/announcements/2014/10/16/platform-becomes-webcomponents
• Mozilla Bricks는 platform.js 사용( 2015.01.15기준)
• dependency (사실상 webcomponents.js 에 통합 되었기 때문에 없다고 보는것이 맞다..)
• weakmap ( ES6의 WeakMap type shim)
• Mutation Observers
WEBCOMPONENTS BROWSER SUPPORT
https://www.polymer-project.org/resources/compatibility.html
엄밀히 말하자면, polymer 의 support 테이블이지만…..
다시 POLYMER?
• Polymer 는 Web Components spec 으로 만들어짐
• 하루에 최소 3개 이상의 디바이스를 사람들은 사용함 -> 동일한 ui 를 각 디바이스에서 보여줄 수 있어야함
• WebComponents 의 Feature를 모두가지고있음
• Custom Element
• Shadow DOM
• HTML Import
• Template
• Everything is an Element === The Polymer world-view
• Functional, Reusable, Interoperable, Encapsulated, Configurable, Programmable, Event Generator, Composable
POLYMER STRUCTUREhttps://github.com/polymer/pica
POLYMER로 만든 예제
• 기본적인 custom element 를 활용
• http://codepen.io/kazikai/pen/dPvvpK
• Carousel
• http://addyosmani.github.io/polymer-ui-carousel/smoke.html
• Selector
• https://www.polymer-project.org/components/core-selector/demo.html
POLYMER 10분만에 만들기-11. Polymer 설치
• Bower: 권장하는 방법: ( bower 는 node.js 가 설치 되어있어야 함 ) : http://bower.io/
• $ bower init
• $ bower install --save Polymer/polymer
• $ bower update ( 새버전 나왔을 경우 )
• zip
• https://www.polymer-project.org/docs/start/getting-the-code.html ( zip down )
• Github
• $ git clone https://github.com/Polymer/polymer.git components/polymer
POLYMER 10분만에 만들기-22. Polymer element 만들기
1. polymer.html 로딩
2. <polymer-element> 를 이용해서 custom element 선언
<link rel="import" href="../bower_components/polymer/polymer.html">
<polymer-element name="my-element" noscript> <template> <span>Hello from <b>my-element</b>. This is my Shadow DOM.</span> </template></polymer-element>
POLYMER 10분만에 만들기-33. 다른 element 사용 하기
• polymer-elment 안에 polymer-element를 사용 가능
• $ bower install Polymer/core-ajax<link rel="import" href="../bower_components/polymer/polymer.html"><link rel="import" href="../bower_components/core-ajax/core-ajax.html">
<polymer-element name="my-element" noscript> <template> <span>I'm <b>my-element</b>. This is my Shadow DOM.</span> <core-ajax url="http://example.com/json" auto response="{{resp}}"></core-ajax> <textarea value="{{resp}}"></textarea> </template></polymer-element>
POLYMER 10분만에 만들기-44. app 만들기
• index.html 생성
• webcomponents.js 로딩 ( polyfill )
<!DOCTYPE html><html> <head> <!-- 1. Load platform support before any code that touches the DOM. --> <script src="bower_components/webcomponentsjs/webcomponents.js"></script> <!-- 2. Load the component using an HTML Import --> <link rel="import" href="elements/my-element.html"> </head> <body> <!-- 3. Declare the element by its tag. --> <my-element></my-element> </body></html>
POLYMER STARTER PROJECT• Starter Project 다운 : https://github.com/Polymer/polymer-tutorial/archive/master.zip
• https://www.polymer-project.org/docs/start/tutorial/intro.html
• HTTP Server 실행
• 간단한 HTTP Server 실행이 필요 함 ( polymer 에서는 python으로 하는법을 추천, 개인적으로 http-server 선호
• python으로 하는법
• 2.x : $ python -m simpeHTTPServer
• 3.x : $ python -m http.server
• node로 하는 법
• $ npm install http-server
• $ http-served
POLYMER CORE EVENT• Polymer 에서 주로 사용하는 기본 이벤트 (순서대로..created>ready>attached>domReady)
• created : element가 만들어 졌을때
• ready : <polymer-element> 가 완전히 준비 되었을때
• attached : DOM에 element 가 붙혀졌을때
• domReady : element 가 light DOM 밑에 존재 하는게 보장 될때
• detached : DOM에서 element 가 제거 될때
• attributeChanged: attribute가 추가/수정 될때Polymer('tag-name', { created: function() { ... }, ready: function() { ... }, attached: function () { ... }, domReady: function() { ... }, detached: function() { ... }, attributeChanged: function(attrName, oldVal, newVal) { //var newVal = this.getAttribute(attrName); console.log(attrName, 'old: ' + oldVal, 'new:', newVal); },});
POLYMER DATA BINDING..<link rel="import" href="/bower_components/polymer/polymer.html"><polymer-element name="greeting-tag"> <!-- outermost template defines the element's shadow DOM --> <template> <ul> <template repeat="{{s in salutations}}"> <li>{{s.what}}: <input type="text" value="{{s.who}}"></li> </template> </ul> <button on-click="{{updateModel}}">Update model</button> <button on-click="{{changeModel}}">change model</button> </template> <script src="greeting-tag.js"></script></polymer-element>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="bower_components/webcomponentsjs/webcomponents.js"></script> <link rel="import" href="elements/greeting-tag.html"></head> <body> <greeting-tag></greeting-tag></body></html>
var count =0;Polymer('greeting-tag', { ready: function() { this.salutations = [ {what: 'Hello', who: 'World'}, {what: 'Goodbye', who: 'DOM APIs'}, {what: 'Hello', who: 'Declarative'}, {what: 'Goodbye', who: 'Imperative'} ]; this.alternates = ['Hello', 'Hola', 'Howdy']; this.current = 0; console.log( "ready" ); }, updateModel: function() { this.current = (this.current + 1) % this.alternates.length; this.salutations[0].what = this.alternates[this.current]; }, changeModel: function(){ this.salutations[0].who = "kazikai" + count++; }, created: function() { console.log( "created" ); }, attached: function () { console.log( "attached" ); }, domReady: function() { console.log( "domReady" ); }, detached: function() { console.log( "detached" ); }, attributeChanged: function(attrName, oldVal, newVal) { console.log( "attributeChanged" ); //var newVal = this.getAttribute(attrName); console.log(attrName, 'old: ' + oldVal, 'new:', newVal); },});
main.html
greeting-tag.html
greeting-tag.js
CSS 스타일링 하기• Shadow DOM 의 BODY 는 ::host
• :: host { display: block; backgroud:blue; }
• Shadow DOM의 Element 의 조상은 :host-context
• :host-context{ display: block; backgroud:blue; }
• Shadow DOM 안의 element style
• ::host <selector> { }
• Preventing FOUC ( FOUC : 외부 css 에 의해 웹페이지 렌더링 되기 전의 모습 )
• custom-element:unresolved{ }
• Light DOM 안에 있는 부분 컨트롤
• ::content <> {}
기존에 있던 위젯을 POLYMER로 • 기존에 만들어져있던 JS 라이브러리 위젯을 Polymer 로 변환 시도 .
• 방법
• 간단히 main을 custom element 로 쪼갠다음 해당 custom element 생성
• 결과 ->실패
• 이유
• 특정 DOM SELECT가 전혀 안됨
• 대부분의 JS 라이브러리는 argument로 해당 dom의 id 값이나 class 값을 전달해줌)
• Shadow DOM은 기존의 DOM API로 선택이 불가능 하다. ( 결국 제어가 안됨 )
• CSS 도 문제
• CSS 는 inline 형태로 어느정도 해결은 가능 ( <template></template> 안에 <link> 요소 선언하면 가능)
기존에 있던 위젯을 POLYMER로 • Polymer 내장 함수를 통해 해당 dom을 컨트롤 할 수 있음
• Polymer({ attached: function(){ //여기 코드 }});
• shadowRoot 를 활용해서 컨트롤
• var $shadow = $( this.shadowRoot );
• $shadow.find(“[selector]”) 로 하면 해당 shadow DOM 컨트롤 가능
• 또는 /deep/ combinator 사용
• var shadowDomElement = document.querySelector(“body /deep/ [selector] “);
• var $shadowDomEl = $( “body /deep/ [selector]” );
• CSS 도 동일
• body /deep/ [selector] { color ; #fff; }
기존에 있던 위젯을 POLYMER로 • 결국 기존에 있던 js 기반 라이브러리 위젯은 polymer 로 쉽게 포팅 불가능
• shadow dom 을 컨트롤 하는 방법이 있지만… 철학에 맞지 않는다고 판단 ( 독립성 )
• /deep/ 을 사용 하면 CSS 캡슐화를 무시함
• 또한 js 로 외부 DOM에서 shadow DOM을 컨트롤 하는 방식은 기존 Polymer 의 철학과는 다름
• Custom Element 가 변경되면 해당 페이지의 UI 가 변경될 가능성이 존재함
• 결론적으로 기존에 있던 js 기반 라이브러리는 polymer로 개발할경우 polymer 포맷에 맞게 다시 개발해야함
기존 웹사이트 쪼개기• 앞에서 말했던 것처럼 기존의 반응형 웹 사이트를 Polymer 로 쪼개 보자
• 새롭게 css/js 를 만드는게 아니라.. /deep/ ::shadow 만을 이용해서 단순히 쪼개기
• 최종적으로 보이는 Output 은 ( Polymer vs not Polymer )
• 대상
• Landy 사이트 템플릿
• https://github.com/paolotripodi/Landy-v1.0
• header/nav/section 별로 나눠져 있으며, 반응형 페이지라 시도 해봄
• 결과물
• https://github.com/kazikai/Landy-v1.0
쪼갠 결과• 메인 HTML 기준 ( index.html vs polymer-index.html ) Polymer 가 훨씬 깔끔한 형태의 HTML 을 보여줌
• CSS/JS 부분의 Shadow DOM 컨트롤 부분 필요에 의한 JS/CSS 수정
• 전체적인 구조만 변경 해보려고했던 작업이라. body /deep/ 일괄적용
• 외부 라이브러리 수정 불가능
• bootstrap.min.css 와 같은 외부 라이브러리는 수정 불가능 -> layout 일부 깨짐
• bootstrap.min.js 도 수정 불가능-> 애니메이션 작동 불가능
• img/css 파일은 파일 구조가 달라짐에 따라 수정이 필요
결론
• 기존의 순수 HTML/CSS/JS 로 제작된 사이트가 Polymer 로 변경 되려면 많은 노력이 필요함
• Polymer는 적용 하려면 개발 초기부터 적용 되어야만 함
• 적용만 하면 유지/보수가 기존의 HTML보다 편할 것이라 생각 되며 main HTML 페이지가 훨씬 간결해짐
• 단 적용하더라도 webcomponents 의 철학에 맞게 사용해야함
• /deep/ ::shadow 와 같이 외부에서 내부 shadowDOM 을 컨트롤 할수있지만. 결국 유지보수가 어려워지며
• Polymer 가 가진 장점을 잃어버림
• 성능적인 부분에서는 모바일에서 많이 느림
• Browser도 일부만 지원하니 상용화에 바로 적용하는것은 무리가 있음
감사합니다. • 참조
• https://www.polymer-project.org/
• http://webcomponents.org/
• http://mozbrick.github.io/
• http://www.w3.org/wiki/WebComponents/