• MDN Webdoc의 ν‘œμ€€, μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈμ™€ ShadowDOM

    2023. 5. 22.

    by. mason.jeong

    πŸ’‘ 21년도 Vuejs 2버전을 사내 κ°œλ°œνŒ€μ— κ΅μœ‘ν•˜κ³ μž μž‘μ„±ν–ˆλ˜ λ¬Έμ„œμž…λ‹ˆλ‹€. μ°Έκ³  ν•΄μ£Όμ„Έμš”! 

     

    MDN Web docs λ₯Ό μ–Όλ§ˆλ‚˜ 많이 μ ‘ν•˜μ‹œλ‚˜μš” ? μš”μ¦˜μ€ λͺ¨λ“  ν”„λ‘ νŠΈμ—”λ“œ ν”„λ ˆμž„μ›Œν¬λ‚˜ λΌμ΄λΈŒλ¦¬μ—μ„œλ„ μ»΄ν¬λ„ŒνŠΈ 기반 아킀텍쳐λ₯Ό κ΅¬ν˜„ν•˜μ—¬ λ³΅μž‘ν•œ ν™”λ©΄μ˜ κΈ°λŠ₯을 κ°„λ‹¨ν•œ λΆ€λΆ„μœΌλ‘œ λ‚˜λˆ„κ³  μ‘°λ¦½ν•˜λŠ” 과정을 톡해 화면을 κ΅¬ν˜„ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. λŒ€ν‘œμ μœΌλ‘œ Vuejs, React 등이 μžˆλŠ”λ°μš”. 이런 ν”„λ ˆμž„μ›Œν¬λŠ” μƒˆλ‘œμš΄ ν‘œμ€€μ„ λ§Œλ“€μ–΄ λ‚Έ 것이 μ•„λ‹Œ 기쑴의 것은 κ·ΈλŒ€λ‘œ 놔두고 μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό 톡해 μ»΄ν¬λ„ŒνŠΈλ₯Ό κ΅¬ν˜„ν–ˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬κ°€ ν”„λ‘ νŠΈμ—”λ“œ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ ν”„λ ˆμž„μ›Œν¬λ₯Ό 많이 μ ‘ν•˜λ©΄μ„œλ„ μ›Ή μ»΄ν¬λ„ŒνŠΈλ“±μ˜ ν‘œμ€€ κΈ°μˆ μ— λŒ€ν•΄μ„œλŠ” 잘 λͺ¨λ₯΄λŠ”것 κ°™μŠ΅λ‹ˆλ‹€. μ›Ή μ»΄ν¬λ„ŒνŠΈλŠ” MDN WebDocs μ—μ„œ κ·Έ μ„€λͺ…을 μ°Ύμ•„ λ³Ό 수 μžˆλŠ”λ°μš”.

     

    MDN Web Docs

    The MDN Web Docs site provides information about Open Web technologies including HTML, CSS, and APIs for both Web sites and progressive web apps.

    developer.mozilla.org

     

    μ›Ή μ»΄ν¬λ„ŒνŠΈλŠ” 화면을 ν‘œμ‹œν•˜κ³  κ·Έ ν‘œμ‹œλœ ν™”λ©΄μ—μ„œ μ œκ³΅ν•˜λŠ” μ—¬λŸ¬κ°€μ§€ κΈ°λŠ₯을 μž¬μ‚¬μš© κ°€λŠ₯ν•œ 쑰각으둜 λ‚˜λˆ„κ³  그것을 λ‹€μ‹œ μ‘°λ¦½ν•˜μ—¬ μ‚¬μš©ν• μˆ˜ μžˆλ„λ‘ μ œκ³΅ν•˜λŠ” λ‹€μ–‘ν•œ 기술의 λͺ¨μŒμ΄λΌκ³  μ„€λͺ…λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

     

    이것이 ν‘œμ€€ 기술둜 κ°œλ°œλ˜κΈ°κΉŒμ§€ μ—¬λŸ¬κ°€μ§€ μ΄μœ λ“€μ΄ μžˆμ„ 수 μžˆκ² μ§€λ§Œ λŒ€ν‘œμ μœΌλ‘œλŠ” 재 μ‚¬μš©μ„±κ³Ό κ·Έλ‘œμΈν•œ 생산성에 λŒ€ν•œ 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•¨μ΄ μ»Έλ˜κ²ƒ κ°™μŠ΅λ‹ˆλ‹€. μš°λ¦¬κ°€ HTML κ³Ό CSS둜 화면을 ν‘œν˜„ν•˜κΈ°μœ„ν•΄ λ°˜λ³΅ν•΄μ•Ό ν•˜λŠ” μž‘μ—…λ“€μ„ 생각해 λ΄…μ‹œλ‹€. λ˜‘κ°™μ€ κΈ°λŠ₯κ³Ό λ””μžμΈμ„ 가지고 μžˆλŠ” HTML 와 CSSλ₯Ό ν•„μš”ν•œ 만큼 λ°˜λ³΅ν•΄μ„œ 코딩을 ν•΄μ£Όμ–΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ›ΉνŽ˜μ΄μ§€λ₯Ό λ™μ μœΌλ‘œ ν‘œν˜„ν•˜κ±°λ‚˜ μ‚¬μš©μžμ—κ²Œ μ—¬λŸ¬κ°€μ§€ κΈ°λŠ₯을 μ œκ³΅ν•˜κΈ° μœ„ν•΄ μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ΄μš©ν•˜λ©΄ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό 효과적으둜 μ œμ–΄ν•  순 μžˆμ§€λ§Œ λ‹€λ₯Έκ³³μ—μ„œ 동일할 κΈ°λŠ₯이 ν•„μš”ν•œ 경우 곡톡 κΈ°λŠ₯으둜 선언을 ν•΄μ£Όκ±°λ‚˜ 같은 μ½”λ“œλ₯Ό μž¬μ‚¬μš© ν–ˆμ–΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ ν•œ νŽ˜μ΄μ§€μ—λŠ” μ„œλ‘œ κ΄€λ ¨μ—†λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œκ°€ λ’€μ£½ 박죽이 되기 마련이고 생산속도λ₯Ό 크게 λŠ˜λ¦΄λ§Œν•œ 방법이 μ œμ•ˆλ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

     

    μ›Ή μ»΄ν¬λ„ŒνŠΈλŠ” μ΄λŸ¬ν•œ λ¬Έμ œλ“€μ„ ν•΄κ²°ν•΄ μ€„μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. λͺ‡κ°€μ§€ κΈ°λŠ₯듀이 μžˆλŠ”λ° ν•˜λ‚˜μ”© μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

     

    μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ

    HTML νƒœκ·ΈλŠ” HTMLμ½”λ“œλ₯Ό μ²˜λ¦¬ν•΄μ£ΌλŠ” λΈŒλΌμš°μ €κ°€ μ œκ³΅ν•˜λŠ” λͺ‡κ°€μ§€ μ•ˆλ˜λŠ” μ˜ˆμ•½μ–΄λΌκ³  λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. HTML νƒœκ·Έλ₯Ό 톡해 μš°λ¦¬λŠ” 화면을 κ΅¬μ„±ν–ˆμŠ΅λ‹ˆλ‹€. μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈλŠ” HTML νƒœκ·Έλ₯Ό μ»€μŠ€ν…€ ν• μˆ˜ μžˆλŠ” κΈ°λŠ₯μž…λ‹ˆλ‹€. λ‚΄κ°€ μ›ν•˜λŠ” μ΄λ¦„μ˜ νƒœκ·Έλ₯Ό λ§Œλ“€κ³  μ‚¬μš©ν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. νƒœκ·Έ μ•ˆμ—λŠ” μžμ‹ μš”μ†Œλ„ ν¬ν•¨λ μˆ˜ μžˆμŠ΅λ‹ˆλ‹€. 

    customElements.define('word-count', WordCount, { extends: 'p' });

     

    μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈλŠ” μœ„μ™€κ°™μ΄ κ°„λ‹¨ν•œ ν˜•νƒœλ‘œ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ°μ‹μœΌλ‘œ μž‘μ„±λœ μžλ°”μŠ€ν¬λ¦½νŠΈ μ½”λ“œκ°€ λ™μž‘ ν•œλ‹€λ©΄ μ΄λŸ¬ν•œ HTML μ½”λ“œλ₯Ό ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    <word-count />

     

    define ν•¨μˆ˜μ—λŠ” νƒœκ·Έμ˜ 이름 말고도 WordCount λΌλŠ”κ²ƒκ³Ό { extends: 'p' } λΌλŠ” νŒŒλΌλ―Έν„°κ°€ μ „λ‹¬λ˜μ—ˆλŠ”λ° λˆˆμΉ˜κ°€ λΉ λ₯Έ 뢄듀은 이미 눈치 μ±„μ…¨μ„μˆ˜λ„ μžˆκ² μ§€λ§Œ WordCount λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ 클래슀, extends, PλŠ” p νƒœκ·Έλ₯Ό μƒμ†ν•œλ‹€λΌλŠ” λœ»μž…λ‹ˆλ‹€. μƒμ†μ΄λΌλŠ” 단어가 μƒμ†Œν•˜μ‹€μˆ˜λ„ μžˆκ² μ§€λ§Œ μ‰½κ²Œ ν‘œν˜„ν•΄μ„œ λ™μΌν•œ κΈ°λŠ₯을 ν•˜λ„λ‘ ν•˜κ² λ‹€ 라고 μ΄ν•΄ν•˜μ‹œλ©΄ λ˜κ² μŠ΅λ‹ˆλ‹€. p νƒœκ·ΈλŠ” λ ˆμ΄μ•„μ›ƒμ—μ„œ 인라인의 성격을 가지고 μžˆμœΌλ―€λ‘œ word-coun νƒœκ·ΈλŠ” 인라인의 속성을 κ°€μ§€κ²Œ λ©λ‹ˆλ‹€.

     

    클래슀λ₯Ό μ‚΄νŽ΄λ³ΌκΉŒμš” ?

    class WordCount extends HTMLElement {
    	consturctor() {
        	super();
        }
        
        function open() {
        	...
        }
    }

     

    ν΄λž˜μŠ€μ—λŠ” μ—¬λŸ¬κ°€μ§€ ν•¨μˆ˜μ™€ λ©”μ„œλ“œκ°€ 포함될 수 μžˆμŠ΅λ‹ˆλ‹€. vuejs 와 react 처럼 라이프 사이클 μ½œλ°±λ„ μ‘΄μž¬ν•©λ‹ˆλ‹€.  ν΄λž˜μŠ€μ— ν¬ν•¨λœ λ©”μ†Œλ“œλŠ” νƒœκ·Έλ‘œ ν™œμš© 될떄 μ΄λ ‡κ²Œ μ‚¬μš©ν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

    <script>
    var count = document.getElementById('word-count');
    count.open();
    </script>

     

    word-count μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ³€μˆ˜μ— μ…€λ ‰νŠΈ ν•œ λ’€ 클래슀처럼 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€. open μ΄λΌλŠ” ν•¨μˆ˜λŠ” world-count 의 λ‚΄λΆ€ κΈ°λŠ₯에 ν¬ν•¨λ˜μ–΄ μžˆμœΌλ―€λ‘œ, world-coint νƒœκ·Έλ₯Ό 톡해 μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό λ³€κ²½ν•˜κ±°λ‚˜ 이벀트λ₯Ό μ£Όκ±°λ‚˜ μ œκ±°ν•˜κ³  ν•˜λŠ” λ“±μ˜ κΈ°λŠ₯을 μž‘μ„±ν•  수 있고 μ΄λŸ¬ν•œ κΈ°λŠ₯을 ν•˜λ‚˜μ˜ 클래슀둜 μΊ‘μŠν™” ν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

     

    Shadow DOM

    shadow dom 은 μ›Ή μ»΄ν¬λ„ŒνŠΈ μ•„ν‚€ν…μ³μ—μ„œ μΊ‘μŠν™”μ˜ μ—°μž₯μ„ μœΌλ‘œ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈλŠ” κΈ°λŠ₯적 μΊ‘μŠν™”λ₯Ό κ΅¬ν˜„ν•  수 있게 ν•΄μ€€λ‹€λ©΄ shadow dom 은 μ—˜λ¦¬λ¨ΌνŠΈμ— μŠ€μ½”ν”„μ™€ 같은 κ°œλ…μ„ μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 블둝 μŠ€μ½”ν”„λŠ” λ³€μˆ˜μ˜ μ ‘κ·Ό λ ˆμ΄μ–΄κ°€ μžˆμ–΄μ„œ ν•΄λ‹Ή 블둝이 μ•„λ‹ˆλ©΄ μ ‘κ·Όν• μˆ˜ μ—†λŠ” κ°œλ…μΈλ°μš”. shadow dom으둜 λ§Œλ“€μ–΄μ§„ μ—˜λ¦¬λ¨ΌνŠΈ νŠΈλ¦¬λŠ” μ™ΈλΆ€μ—μ„œ μ ‘κ·Όν•  수 없도둝 μ œν•œμ„ μ€„μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

    let shadow = elementRef.attachShadow({ mode: 'open' });
    let shadow = elementRef.attachShadow({ mode: 'close' });

     

    elementRefλŠ” 이미 μ…€λ ‰νŠΈ 된 μ—˜λ¦¬λ¨ΌνŠΈ μΈμŠ€ν„΄μŠ€μž…λ‹ˆλ‹€. 여기에 attachShadow ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄ μƒˆλ‘œμš΄ shadow dom root κ°€ μƒμ„±λ©λ‹ˆλ‹€. shadow dom root μ—λŠ” 일반 λ”μ²˜λŸΌ λ‹€λ₯Έ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ μ‚­μ œ ν• μˆ˜λ„ 있고 이벀트 λ¦¬μŠ€λ„ˆλ₯Ό 생성해 μ€„μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

     

    Shadow DOM 의 attachment - 좜처 MDN

     

    shadow DOM 이 일반 μ—˜λ¦¬λ¨ΌνŠΈμ™€ μ–΄λ–»κ²Œ μž‘μš©ν• μˆ˜ μžˆλŠ”μ§€ 보여주고 μžˆμŠ΅λ‹ˆλ‹€. shadow dom 은 μ‹€μ œ 일반 돔 νŠΈλ¦¬μ— λΆ€μ°©λ˜κΈ° μ „κΉŒμ§€λŠ” λ Œλ”λ§ λ˜μ§€ μ•ŠμœΌλ©° 뢀착이 됨과 λ™μ‹œμ— λ Œλ”λ§μ΄ 되기 λ•Œλ¬Έμ—. μ—¬λŸ¬κ°€μ§€ μžμ‹ μš”μ†Œλ₯Ό ν¬ν•¨ν•œ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ œμž‘ν•˜μ—¬ μž¬μ‚¬μš© ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 

     

    이제 shadow dom 을 μ‚¬μš©ν•˜λŠ” 방법을 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

    class SimpleModal extends HTMLElment {
    	construct() {
        	super();
            
            // shadowDOM 생성
            this.attachShadow({ mode: 'open' });
            // λͺ¨λ‹¬μ˜ ν‘œμ‹œ μ—¬λΆ€
            this._visible = false;
            // λͺ¨λ‹¬μ˜ μ—˜λ¦¬λ¨ΌνŠΈμ™€ μŠ€νƒ€μΌ ν‘œν˜„
            this.shadowRoot.innerHTML = `
            	<div class="modal_wrap">
                	...
                </div>
            `;
        }
        
        // 가상 νŠΈλ¦¬κ°€ document 에 μ—°κ²°λœ ν›„ μ‹€ν–‰
        connectedCallback() {
        	this._modal = this.shadowRoot.querySelector('.modal-wrap');
            this.shadowRoot.querySelect('.close').addEventListener('click', this._hide.bind(this));
            
            this.shadowRoot.querySelector('.modal-box').style.backgroundColor = this.getAttribute('bgcolor');
        }
        
        // λͺ¨λ‹¬μ„ λ‹«μŒ
        _hide() {
        	this._visible = true;
            this._modal.style.display = 'none';
        }
        
        // λͺ¨λ‹¬μ„ μ—Ό
        show() {
        	this._visible = false;
            this._modal.style.display - 'block';
        }
    }
    
    // μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈ 등둝
    customElements.define('simple-modal', SimpleModal);

     

    SimpleModal 은 μ»€μŠ€ν…€ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό 톡해 shadow dom 을 μƒμ„±ν•˜κ³  λ‚΄λΆ€ ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄ shadow element λ₯Ό 컨트둀 ν•΄μ£Όμ—ˆμŠ΅λ‹ˆλ‹€. μ—˜λ¦¬λ¨ΌνŠΈ ν΄λž˜μŠ€κ°€ μΈμŠ€ν„΄μŠ€ν™” λ λ•Œ (λ”μ—μ„œ λ Œλ”λ§ λ λ•Œ) shadow dom 을 μƒμ„±ν•˜μ—¬ 일반 μ—˜λ¦¬λ¨ΌνŠΈμ— μ ‘μ°© 될수 μžˆλŠ” μƒνƒœκ°€ λ©λ‹ˆλ‹€. 

     

    ν”„λ‘ νŠΈμ—”λ“œ λΌμ΄λΈŒλŸ¬λ¦¬λ‚˜ ν”„λ ˆμž„μ›Œν¬λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  μžλ°”μŠ€ν¬λ¦½νŠΈμ™€ HTML νƒœκ·Έλ§Œ 가지고 μ»΄ν¬λ„ŒνŠΈλ₯Ό κ΅¬ν˜„ν• μˆ˜ μžˆλ‹€λŠ” 점이 μ‹ μ„ ν–ˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ ν‘œμ€€ 기술이 κ³„μ†ν•΄μ„œ λ°œμ „λ˜κ³  μžˆμ§€λ§Œ μ•„μ§κΉŒμ§€λŠ” react와 vuejs 의 κΈ°λŠ₯을 λ”°λΌκ°€κΈ°μ—λŠ” λΆ€μ‘±ν•œ 뢀뢄이 많이 λ³΄μž…λ‹ˆλ‹€. ν‘œμ€€ κΈ°μˆ μ—λŠ” 이 외에도 template κ³Ό slot λ“±μ˜ μ›Ή μ»΄ν¬λ„ŒνŠΈλ₯Ό μœ„ν•œ κΈ°μˆ λ“€μ΄ μžˆμœΌλ―€λ‘œ λ‹€μŒ ν¬μŠ€νŒ…μ—μ„œ 닀뀄보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

     

     

    전체 μ½”λ“œλŠ” μ—¬κΈ°μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

     

    GitHub - meju7015/web-frontend-study: μ›Ή ν”„λ‘ νŠΈμ—”λ“œ μŠ€ν„°λ””λ₯Ό μœ„ν•œ Repository

    μ›Ή ν”„λ‘ νŠΈμ—”λ“œ μŠ€ν„°λ””λ₯Ό μœ„ν•œ Repository. Contribute to meju7015/web-frontend-study development by creating an account on GitHub.

    github.com

     

     

     

     

    'Tech > Frontend' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€

    MDN Webdoc의 ν‘œμ€€, Template & Slot  (0) 2023.05.23
    Vue2λ₯Ό AWS S3에 λ°°ν¬ν•˜κ³  μš΄μ˜ν•΄λ³΄μž  (0) 2023.05.04

    λŒ“κΈ€