Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The State of Web Components
Search
Shogo Sensui
September 24, 2017
Technology
9
9.1k
The State of Web Components
2017年9月24日に開催された HTML5 Conference 2017 の「The State of Web Components」のセッション資料です。
Shogo Sensui
September 24, 2017
Tweet
Share
More Decks by Shogo Sensui
See All by Shogo Sensui
三年間の関わりから見る PR TIMES エンジニアリングの変化 / Transition of PRTimes Engineering
1000ch
0
2.2k
EU のデジタル市場法と Apple / DMA and Apple
1000ch
0
130
Web Share API
1000ch
0
150
2023 年の Web 開発のベースライン / Web Development Baseline 2023
1000ch
0
57
開発生産性と組織 / Productivity and Organization
1000ch
0
1.2k
なぜ私達は働くのか / Why We Work?
1000ch
0
82
新しいメルカリ Web とそのパフォーマンス / The New Mercari Web and its performance
1000ch
0
90
Web Standards Interop 2022
1000ch
0
320
パフォーマンスを高める CSS / Performance Optimized CSS
1000ch
1
820
Other Decks in Technology
See All in Technology
Model Mondays S2E01: Advanced Reasoning
nitya
0
420
Copilot Agentを普段使いしてわかった、バックエンド開発で使えるTips
ykagano
1
1.3k
AWS アーキテクチャ作図入門/aws-architecture-diagram-101
ma2shita
24
8.9k
20250623 Findy Lunch LT Brown
3150
0
650
DroidKnights 2025 - Jetpack XR 살펴보기: XR 개발은 어떻게 이루어지는가?
heesung6701
1
150
AIにどこまで任せる?実務で使える(かもしれない)AIエージェント設計の考え方
har1101
3
1.2k
AWS全冠したので振りかえってみる
tajimon
0
150
AWS と定理証明 〜ポリシー言語 Cedar 開発の舞台裏〜 #fp_matsuri / FP Matsuri 2025
ytaka23
9
2.6k
新規プロダクト開発、AIでどう変わった? #デザインエンジニアMeetup
bengo4com
0
490
CIでのgolangci-lintの実行を約90%削減した話
kazukihayase
0
320
DenoとJSRで実現する最速MCPサーバー開発記 / Building MCP Servers at Lightning Speed with Deno and JSR
yamanoku
1
160
Definition of Done
kawaguti
PRO
5
390
Featured
See All Featured
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Build The Right Thing And Hit Your Dates
maggiecrowley
36
2.7k
Rails Girls Zürich Keynote
gr2m
94
14k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.8k
Embracing the Ebb and Flow
colly
86
4.7k
Stop Working from a Prison Cell
hatefulcrawdad
269
20k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
43
2.4k
KATA
mclloyd
29
14k
Adopting Sorbet at Scale
ufuk
77
9.4k
GraphQLとの向き合い方2022年版
quramy
46
14k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
Transcript
)5.-$POGFSFODF 4IPHP4FOTVJBLB!DI 5IF4UBUFPG8FC$PNQPOFOUT
!DI
‣ 4IPHP4FOTVJ ‣ ؎ٝة٦طحزדכDIדׅ ‣ $ZCFS"HFOU *OD ‣ 8FC*OJUJBUJWF$FOUFS ‣
4PGUXBSF&OHJOFFS ‣ 8FC䪮遭Ⰻ菙ָ㥨ֹדׅ ‣ 044崞⹛׃גתׅ
馄鸞劤ָ⳿תׅ 涪㡰✮㹀
8IZ8FC$PNQPOFOUT
)5.- $44 8FC涪罏
8FCחֶֽ鿇ㅷךꨇ׃ׁ ‣ )5.-ה$44חأ؝٦فָ㶷㖈׃זְ ‣ 铣鴥$44ך䕦갟眔㔲ָ鎘濼זְ ‣ せ瑞ָ遼瑱׃זְ״ֲծ䌢ח䠐陎ׅ䗳銲ָ֮ ‣ ⡲鿇ㅷⱄⵃ欽׃חְֻ ‣
)5.- $44 +BWB4DSJQUתה➬穈ָזְ ‣ תה鿇ㅷꂁ䋒ׅؒ؝ءأذيָזַ
نةٝ⡲חכ˘ GBODZCVUUPO
<button> fancy button </button> button { background: #0086b3; color: white;
padding: 1em; border-radius: 0.5em; border: none; } )5.-ה$44剅ֽל0,
GBODZCVUUPO
GBODZCVUUPO GBODZCVUUPO
<button class="a"> fancy button </button> <button class="b"> fancy button </button>
button { color: white; padding: 1em; border-radius: 0.5em; border: none; } button.a { background: #0086b3; } button.b { background: #008080; }
GBODZCVUUPO GBODZCVUUPO
GBODZCVUUPO GBODZCVUUPO GBODZCVUUPO
GBODZCVUUPO GBODZCVUUPO GBODZCVUUPO PWBM TRVBSF
fancy button </button> <button class="b"> fancy button </button> <button class="c">
fancy button </button> <button class="oval"> oval </button> <button class="square"> border-radius: 0.5em; border: none; } button.a { background: #0086b3; } button.b { background: #008080; } button.oval { ... }
GBODZCVUUPO GBODZCVUUPO GBODZCVUUPO PWBM TRVBSF
<fancy-button color="a"> fancy button </fancy-button> <fancy-button color="b"> fancy button </fancy-button>
<fancy-button color="c"> fancy button </fancy-button> <oval-button>oval</oval-button> <square-button>square</square-button>
4IBEPX%0. $VTUPN&MFNFOUT 5FNQMBUFT )5.-*NQPSUT ˟׳התד
˟䎃猧植㖈 4IBEPX%0. $VTUPN&MFNFOUT 5FNQMBUFT &4.PEVMFT
4IBEPX%0.
4IBEPX%0.הכ ‣ )5.-ծ$44ծ+BWB4DSJQUך䕦갟眔㔲ꣲ㹀ׅ ‣ مأزהז銲稆חTIBEPX3PPU欰װ׃ծך⚥ד饯ֿֿה4IBEPX %0.ⰻח殅 ‣ 4IBEPX%0.㢩鿇ַך䕦갟ꣲ㹀ׅ ‣ TIBEPX3PPUפך،ؙإأꣲ㹀涸ח׃ծ䮶莸ְ䬐⥂ׅ
‣ TIBEPX3PPUפ،ؙإأדֹPQFOٌ٦سהծ黪倖ׅDMPTFEٌ٦سָ֮
const button = document.querySelector('button'); const shadowRoot = button.attachShadow({ mode: 'open'
// or 'close' }); // readonly property console.log(button.shadowRoot); 4IBEPX%0.ך欰װ׃倯
GBODZCVUUPO ⢽ִלְֲֲֿنةٝ
<button> fancy button </button> ֲֿ剅ֽءٝفٕ˘ <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; }ɹ </style>
<button> #shadow-root fancy button </button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button>
<button> #shadow-root fancy button </button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; }ɹ </style> <button> <slot></slot> </button>
<button> #shadow-root fancy button </button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button> 4DPQFE
$VTUPN&MFNFOUT
$VTUPN&MFNFOUTהכ ‣ 杝荈ך)5.-銲稆㹑鎉ׅ ‣ )5.-ד㹑鎉涸חⵃ欽דֹ ‣ %0."1*鸐ׄגㄏ⟀涸חⵃ欽דֹ ‣ ⟣䠐ך䮶莸ְ㹀纏ׅ ‣
㹀纏ׁٓ؎ؿ؟؎ؙٕؿحؙׅ
class FancyButton extends HTMLElement { constructor() { ... } connectedCallback()
{ ... } disconnectedCallback() { ... } attributeChangedCallback() { ... } adoptedCallback() { ... } } ؕأةي銲稆ٓ؎ؿ؟؎ؙٕ
䖞勻ך8FC鿇ㅷךⱄⵃ欽 ‣ 鿇ㅷ圓䧭ׅ)5.-鎸鶢ׅ ‣ $44ח״أة؎ؚٔٝ黝欽ׅ ‣ $44ؿ؋؎ٕٗ٦سׅծTUZMF銲稆剅ֻծFUD ‣ +BWB4DSJQUח״䮶莸ְ黝欽ׅ ‣
+BWB4DSJQUؿ؋؎ٕٗ٦سׅծTDSJQU銲稆剅ֻծFUD
GBODZCVUUPO نةٝ⢪ְְ˘
.fancy { background: #0086b3; color: white; padding: 1em; border-radius: 0.5em;
border: none; } CVUUPODTT
CVUUPOKT document .querySelector('.fancy') .addEventListener('click', () => { //... });
<button class="fancy"> fancy button </button> JOEFYIUNM
<link rel="stylesheet" href="button.css"> ... <button class="fancy"> fancy button </button> ...
<script src="button.js"></script> 穈さׇג⢪ֲ
None
class FancyButton extends HTMLElement { connectedCallback() { this.innerHTML = `
<style>button { … }</style> <button>fancy button</button> `; } } customElements .define('fancy-button', FancyButton);
<fancy-button> fancy button </fancy-button> GBODZCVUUPO GBODZCVUUPO⢪ִ
<fancy-button> <style> button { background: #0086b3; color: white; padding: 1em;
border-radius: 0.5em; border: none; } </style> <button> fancy button </button> </fancy-button> /PUTDPQFE
4IBEPX%0. $VTUPN&MFNFOUT
class FancyButton extends HTMLElement { connectedCallback() { this.innerHTML = `
<style>button { … }</style> <button>fancy button</button> `; } } customElements .define('fancy-button', FancyButton);
class FancyButton extends HTMLElement { connectedCallback() { this.shadowRoot.innerHTML = `
<style>button { … }</style> <button><slot></slot></button> `; } } customElements .define('fancy-button', FancyButton);
<fancy-button> <style> button { background: #0086b3; color: white; padding: 1em;
border-radius: 0.5em; border: none; } </style> <button> fancy button </button> </fancy-button>
<fancy-button> #shadow-root <style> button { background: #0086b3; color: white; padding:
1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button> fancy button </fancy-button> 4DPQFE
5FNQMBUFT
5FNQMBUFTהכ ‣ ꬊ崞䚍ז)5.-銲稆㹑鎉ׅ ‣ ذٝفٖ٦زה׃ג)5.-銲稆䪔ִ ‣ 䖞勻ךعحؙ涸ז،فٗ٦ثׇ׆ח幥
<div style="display:none;"> <p>This is an image</p> <img src="foo.jpg" alt=""> </div>
4FOEBSFRVFTU
<script type="text/template"> <p>This is an image</p> <img src="foo.jpg" alt=""> </script>
&WBMXJUIJOOFS)5.-
<template> <p>This is an image</p> <img src="foo.jpg" alt=""> </template> *OFSU✨
4IBEPX%0. $VTUPN&MFNFOUT 5FNQMBUFT
class FancyButton extends HTMLElement { connectedCallback() { this.shadowRoot.innerHTML = `
<style>button { … }</style> <button><slot></slot></button> `; } } customElements .define('fancy-button', FancyButton);
<template> <style>button { … }</style> <button><slot></slot></button> </template> <script> class FancyButton
extends HTMLElement { // ... } customElements .define('fancy-button', FancyButton); </script>
<link rel="import" href="fancy-button.html"> <fancy-button> fancy button </fancy-button>
)5.-*NQPSUT… IUUQTHJUIVCDPNXDXFCDPNQPOFOUTJTTVFTJTTVFDPNNFOU
)5.-.PEVMFT… IUUQTHJTUHJUIVCDPN5BLBZPTIJ,PDIJGEDFEGECCEBGFGF
import fancy from './fancy.html' as HTMLTemplateElement; export class FancyButton extends
HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }).appendChild(fancy.content.cloneNode(true)); } }
&4.PEVMFT
&4.PEVMFTהכ ‣ &4.PEVMFTךـٓؐؠ㹋鄲 ‣ TDSJQUUZQFˑNPEVMF˒ד+BWB4DSJQUؿ؋؎ٕٗ٦سׅ ‣ TDSJQUOPNPEVMFדꬊ㼎䘔橆㞮罋䣁ׅ ‣ &4.PEVMFTך/PEFKT㹋鄲 ‣
NKT&4.PEVMFTך+BWB4DSJQUؿ؋؎ٕה׃גٗ٦سׅ
export default class FancyButton { ... } GBODZCVUUPOKT
import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes
from 'prop-types'; import FancyButton from './fancy-button.js'; JOEFYKT
<script type="module"> import FancyButton from './fancy-button.js'; customElements .define('fancy-button', FancyButton); </script>
4IBEPX%0. $VTUPN&MFNFOUT &4.PEVMFT
class FancyButton extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open'
}).innerHTML = ` <style>button { … }</style> <button><slot></slot></button> `; } } customElements .define('fancy-button', FancyButton);
export default class FancyButton extends HTMLElement { connectedCallback() { this.attachShadow({
mode: 'open' }).innerHTML = ` <style>button { … }</style> <button><slot></slot></button> `; } }
<fancy-button> fancy button </fancy-button> <script type="module"> import FancyButton from './fancy-button.js';
customElements .define('fancy-button', FancyButton); </script>
8FCחֶֽ鿇ㅷךꨇ׃ׁ ‣ )5.-ה$44חأ؝٦فָ㶷㖈׃זְ ‣ 铣鴥$44ך䕦갟眔㔲ָ鎘濼זְ ‣ せ瑞ָ遼瑱׃זְ״ֲծ䌢ח䠐陎ׅ䗳銲ָ֮ ‣ ⡲鿇ㅷⱄⵃ欽׃חְֻ ‣
)5.- $44 +BWB4DSJQUתה➬穈ָזְ ‣ תה鿇ㅷꂁ䋒ׅؒ؝ءأذيָזַ
4IBEPX%0. $VTUPN&MFNFOUT &4.PEVMFT OQN ZBSO 8FCחֶֽ鿇ㅷךꨇ׃ׁ ‣ )5.-ה$44חأ؝٦فָ㶷㖈׃זְ ‣ 铣鴥$44ך䕦갟眔㔲ָ鎘濼זְ
‣ せ瑞ָ遼瑱׃זְ״ֲծ䌢ח䠐陎ׅ䗳銲ָ֮ ‣ ⡲鿇ㅷⱄⵃ欽׃חְֻ ‣ )5.- $44 +BWB4DSJQUתה➬穈ָזְ ‣ תה鿇ㅷꂁ䋒ׅؒ؝ءأذيָזַ
1PMZNFS4VNNJU JO$PQFOIBHFO
#PXFSJTEFQSFDBUFE
6TFOQN ZBSO
// fancy-button v1.0.0 customElements .define('fancy-button', FancyButton); // fancy-button v1.1.0 customElements
.define('fancy-button', FancyButton); ZBSO⢪ֲץֹ椚歋 ☠ ⣛㶷ٌآُ٦ٕؿٓحزזخٔ٦ד鍑寸דֹ✨
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
8FC$PNQPOFOUTTBOECPY IUUQTDIHJUIVCJPXFCDPNQPOFOUTTBOECPY
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
✅ ✅ $VTUPN&MFNFOUTW 4IBEPX%0.W 5FNQMBUFT &4.PEVMFT ✅ ✅ ✅ ✅
✅ ✅ ✅ ✅ ✅ ✅ 䎃猧ـٓؐؠ؟ه٦ز
8FC$PNQPOFOUT JT BWBJMBCMFOPX PO UIFNPCJMFXFC✨
None
:PV5VCFJTCVJMU POUIFUPQPG1PMZNFS
None
6TFXFCDPNQPOFOUTKT ‣ $VTUPN&MFNFOUTWךهٔؿ؍ٕ ‣ 4IBEZ%0.4IBEPX%0.ך%0."1*هٔؿ؍ٕ ‣ 4IBEZ$444IBEPX%0.ךأة؎ٕꟼ鸬هٔؿ؍ٕ ‣ )5.-*NQPSUT
8IZ4IBEZ%0. ‣ %0.خٔ٦ך،ؙإ؟ⵖ䖴ׅךָꨇ׃ְ ‣ ぐ珏%0."1*װ/PEF-JTUךؒىُٖ٦زָꨇ׃ְ ‣ EPDVNFOUCPEZ瘝ך،ؙإ؟♳剅ֹדֹזְ ‣ ؝٦سꆀָ花㣐חז♳ծػؿؓ٦وٝأח䕦갟ׅ
‣ 4IBEZ%0."1*➜׃ג،ؙإأׇׁ ‣ 㸜㹀䚍⥂אאծػؿؓ٦وٝأ⳿ׅ
None
8FC$PNQPOFOUT JTBMTP BWBJMBCMFOPX PO UIFEFTLUPQXFC
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
"DDFTTJCJMJUZ ‣ 4IBEPX%0.ך)5.-،ؙإءـٕח ‣ 鸐䌢ך%0.ず圫חծإوٝذ؍ؙأ䠐陎ׅ ‣ )5.-ֽד♶⼧ⴓז㜥さכծ8"*"3*"ד؟ه٦زׅ ‣ 孡חזךכأ؝٦فⰻפך،ؙإأ ‣
4IBEPX%0.ָꪪ⳿ׁגְֽ ‣ ،ؙإءؽٔذ؍ָ⡚ְ؝ٝه٦طٝز⢪ֲ㜥さכ˘
<fancy-button> #shadow-root fancy button </fancy-button> <style> button { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <button> <slot></slot> </button> &YQPTFE
<fancy-button> #shadow-root fancy button </fancy-button> <style> div { background: #0086b3;
color: white; padding: 1em; border-radius: 0.5em; border: none; } </style> <div role="button" tabindex="0"> <slot></slot> </div> &YQPTFE
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
-PBE1FSGPSNBODF ‣ TDSJQUח״؝ٝه٦طٝزךٗ٦س ‣ ؙٔؒأز侧כ)551ד֮ל孡ח׃ֺׅזֻג葺ְ ‣ ؝ٝه٦طٝزך+BWB4DSJQUؿ؋؎ٕכNJOJGZׅ ‣ UZQFˑNPEVMF˒㾩䚍ח״EFGFSٗ٦س ‣
ؔفءّٝדBTZOD㾩䚍➰♷דֹ
TDSJQUח״ぐ珏ٗ٦س IUUQTIUNMTQFDXIBUXHPSHNVMUJQBHFTDSJQUJOHIUNMUIFTDSJQUFMFNFOU
ثُ٦صؚٝه؎ٝز ‣ ٔا٦أ㙵鴥ךַٍؗحءُׅךַ ‣ 㙵鴥כ剑傍ֻٖٝتֲָׁؚٔٝծⴱ劍ٗ٦سָ曯暨חז ‣ ״כ$BDIF$POUSPMقحتװ4FSWJDF8PSLFSזודٍؗحءُ׃ְ ‣ ⴱ劍ٗ٦س傍ְ ‣
MJOLSFMˑQSFMPBE˒ד"5'חꟼٔا٦أٗ٦س׃גֶֻ ‣ 如㔐鼂獳ח䗳銲זٔا٦أכMJOLSFMˑQSFGFUDI˒דٗ٦س׃גֶֻ
‣ #SPXTFS4VQQPSU ‣ "DDFTTJCJMJUZ ‣ -PBE1FSGPSNBODF ‣ 3FOEFS1FSGPSNBODF
3FOEFS1FSGPSNBODF ‣ -JHIU%0.ה4IBEPX%0.ך䊴 ‣ 4IBEPX%0.ךךךכـٓؐؠ㹋鄲ך剑黝⻉ח㨻י״ֲ ‣ ע㣐䊴כזְ⦐➂ך✮䟝דׅ ‣ 7JSUVBM%0.ח״䊴ⴓ䲽歗ך⡭㖑 ‣
➙תד鸐3FBDUזוך7JFXٓ؎ـٓٔה穈さׇ ‣ 8FC$PNQPOFOUTⰻד䊴ⴓ䲽歗㹋倵ׅ
import React from 'react'; export default class Button extends React.Component
{ handleClick(e) { if (this.props.onClick) { this.props.onClick(e); } } render() { const handleClick = this.handleClick.bind(this); return ( <fancy-button onClick={handleClick}> {this.props.children} </fancy-button> ); } }
1PMZNFS-BCTMJUIUNM ‣ 5BHHFE5FNQMBUF-JUFSBMדUFNQMBUF⢪ֲ➬穈 ‣ IUNMAAדذٝفٖ٦ز⡲ծSFOEFS ד)5.-欰䧭ׅ ‣ SFOEFS ד床ׅ⹛涸ז鿇ⴓך䊴ⴓ䲽歗ׅ
const helloTemplate = (name) => html`<div>Hello ${name}!</div>`; // renders <div>Hello
Steve!</div> to the document body render(helloTemplate('Steve'), document.body); // updates to <div>Hello Kevin!</div>, but only updates the ${name} part render(helloTemplate('Kevin'), document.body);
import { html, render } from './lit-html.js'; export default class
IconButton extends HTMLElement { connectedCallback() { this.attachShadow({ mode: 'open' }); render(this.template, this.shadowRoot); } get template() { return html` <style>...</style> <button> <i class="${this.getAttribute('icon')}"></i> <slot></slot> </button> `; } };
תה ‣ 8FC$PNQPOFOUTחꟼׅぐ珏➬圫ָ㸜㹀׃גֹ ‣ ـٓؐؠ㹋鄲滠㹋ח鹌ծ暴חٌغ؎ٕ8FCדכه ٔؿ؍ٕז׃ד⢪ִ ‣ ➙⢪גְ䪮遭أةحؙח《鴥דְֽ ‣ ـٓؐؠⰻ鿇Ⳣ椚ך剑黝⻉䖉אאծطحزٙ٦ؙ
ꟼ鸬כ㛇劤ח屟ثُ٦صؚٝד0,
:PVBSFSFBEZUPVTF 8FC$PNQPOFOUT✨
5IBOLZPV !DI "DI