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
Third Party Hell
Search
Matthias Le Brun
March 28, 2018
Technology
580
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Third Party Hell
Matthias Le Brun
March 28, 2018
More Decks by Matthias Le Brun
See All by Matthias Le Brun
GraphQL, Pothos & SQLite: a perfect match
bloodyowl
0
120
(why the hell did I) build a GraphQL client for the browser
bloodyowl
0
160
Boxed: bringing algebraic types to TypeScript
bloodyowl
0
190
leveraging (algebraic data) types to make your UI rock @ jsheroes
bloodyowl
0
340
Leveraging (algebraic data) types to make your UI rock solid
bloodyowl
0
520
La drôle d'histoire de JavaScript
bloodyowl
0
410
Healthy Code Collaboration
bloodyowl
0
370
Simplify your UI management with (algebraic data) types
bloodyowl
0
860
Simplify your UI management with (algebraic data) types
bloodyowl
1
590
Other Decks in Technology
See All in Technology
第3回しろおびセキュリティスポンサーセッション
log0417
0
190
ラジオの科学
frievea
0
310
FORENSIA: ローカルLLMフォレンジックハーネス
sumeshi
2
390
Digitization部 紹介資料
sansan33
PRO
2
7.7k
Breaking the Seal: Static Deobfuscation of Compiled V8 JavaScript Bytecode Malware
hshrzd
0
760
その“隠したつもり”が命取り ── 自前と平文をやめて「正解」に委ねる
kuroneko13
0
120
制約理論(ToC)入門 2026版
recruitengineers
PRO
8
2.3k
Genie Codeハンズオン基礎編
taka_aki
1
120
JavaScript 研修 (2026)
recruitengineers
PRO
2
540
QAエンジニア起点で進める、SmartHRにおける信頼性向上について
kaomi_wombat
1
140
Agent 時代の Kaggle 展望 / kaggle-in-the-agentic-era
upura
1
720
修正PRを食べてレビュースキルが賢くなる:Claude Codeによる自己改善サイクル
yuyaumetsu
6
1.5k
Featured
See All Featured
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
520
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.4k
Become a Pro
speakerdeck
PRO
31
6.2k
The Curse of the Amulet
leimatthew05
2
14k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.1k
Music & Morning Musume
bryan
47
7.3k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.8k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
440
KATA
mclloyd
PRO
35
15k
Transcript
Third-party hell Making code for hostile environments
Matthias Le Brun @bloodyowl Be
third-party?
First party page You
None
use cases: widgets, players
not your page not your domain not controlled
strategy?
Inject DOM elements in the first party page?
First party CSS resets & defaults will fuck your page
up in unexpected ways
What you wrote Nice Nice What shows up Nice Nice
-> Nice Nice
Inline styles or ensure your stylesheet is always last in
the DOM
• unset all properties • unset all pseudo elements properties
• unset weird vendor selectors (some use them) You need to:
Alpha() AlphaImageLoader() :active additive-symbols (@counter-style) !::after (:after) align-content align-items align-self
all <an-plus-b> <angle> animation animation-delay animation-direction animation-duration animation-fill-mode animation-iteration-count animation-name animation-play-state animation-timing- function @annotation annotation() attr() Barn() BasicImage() BlendTrans() Blinds() Blur() !::backdrop backface-visibility background background-attachment background-blend-mode background-clip background-color background-image background-origin background-position background-repeat background-size <basic- shape> !::before (:before) <blend-mode> block-size blur() border border-block-end border-block-end-color border-block-end-style border-block-end-width border-block-start border-block-start-color border-block-start-style border-block-start-width border-bottom border-bottom-color border-bottom-left-radius border-bottom-right-radius border-bottom-style border-bottom-width border-collapse border-color border-image border-image-outset border-image-repeat border- image-slice border-image-source border-image-width border-inline-end border-inline-end-color border-inline-end-style border-inline-end-width border-inline- start border-inline-start-color border-inline-start-style border-inline-start-width border-left border-left-color border-left-style border-left-width border-radius border-right border-right-color border-right-style border-right-width border-spacing border-style border-top border-top-color border-top-left- radius border-top-right-radius border-top-style border-top-width border-width bottom @bottom-center box-decoration-break box-shadow box-sizing break-after break-before break-inside brightness() CheckerBoard() Chroma() Compositor() calc() caption-side caret-color ch @character-variant character-variant() @charset :checked circle() clear clip clip-path cm <color> color column-count column-fill column-gap column-rule column-rule-color column-rule-style column- rule-width column-span column-width columns content contrast() <counter> counter-increment counter-reset @counter-style cross-fade() cubic-bezier() !::cue cursor <custom-ident> DropShadow() :default deg :dir direction :disabled display dpcm dpi dppx drop-shadow() Emboss() Engrave() element() ellipse() em :empty empty-cells :enabled ex Fade() FlipH() FlipV() fallback (@counter-style) filter <filter-function> :first :first-child !::first-letter (:first- letter) !::first-line (:first-line) :first-of-type fit-content() <flex> flex flex-basis flex-direction flex-flow flex-grow flex-shrink flex-wrap float :focus font @font-face font-family font-family (@font-face) font-feature-settings font-feature-settings (@font-face) @font-feature-values font-kerning font- language-override font-size font-size-adjust font-stretch font-stretch (@font-face) font-style font-style (@font-face) font-synthesis font-variant font- variant (@font-face) font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-variation-settings (@font-face) font-weight font-weight (@font-face) format() format() (@font-face) fr frames() <frequency> :fullscreen Glow() Gradient() GradientWipe() Gray() grad <gradient> grayscale() grid grid-area grid-auto-columns grid-auto-flow grid-auto-rows grid-column grid-column-end grid-column-gap grid-column-start grid-gap grid-row grid-row-end grid-row-gap grid-row-start grid-template grid-template-areas grid-template-columns grid- template-rows Hz hanging-punctuation height height (@viewport) @historical-forms :hover hsl() hsla() hue-rotate() hyphens ICMFilter() Inset() Invert() Iris() <ident> <image> image() image-orientation image-rendering image-resolution image-set() @import in :in-range :indeterminate inherit initial inline- size inset() <integer> :invalid invert() isolation justify-content kHz @keyframes Light() :lang :last-child :last-of-type leader() :left left @left-bottom <length> letter-spacing line-break line-height linear-gradient() :link list-style list-style-image list-style-position list-style-type local() MaskFilter() Matrix() MotionBlur() margin margin-block-end margin-block-start margin-bottom margin-inline-end margin-inline-start margin-left margin-right margin-top mask mask-clip mask-composite mask-image mask-mode mask-origin mask-position mask-repeat mask-size mask-type matrix() matrix3d() max-height max-height (@viewport) max-width max-width (@viewport) max-zoom (@viewport) @media min-block-size min-height min-height (@viewport) min-inline-size min-width min-width (@viewport) min-zoom (@viewport) minmax() mix-blend-mode mm ms ms-filter-alpha() ms-filter-basicimage() ms-filter-blendtrans() ms-filter-blur() ms-filter- chroma() ms-filter-compositor() ms-filter-dropshadow() ms-filter-emboss() ms-filter-engrave() ms-filter-fliph() ms-filter-flipv() ms-filter-glow() ms- filter-gray() ms-filter-icmfilter() ms-filter-invert() ms-filter-light() ms-filter-maskfilter() ms-filter-matrix() ms-filter-motionblur() ms-filter- redirect() ms-filter-revealtrans() ms-filter-shadow() ms-filter-wave() ms-filter-xray() ms-proceduralsurface-alphaimageloader() ms-proceduralsurface- gradient() ms-transition-barn() ms-transition-blinds() ms-transition-checkerboard() ms-transition-fade() ms-transition-gradientwipe() ms-transition-inset() ms-transition-iris() ms-transition-pixelate() ms-transition-radialwipe() ms-transition-randombars() ms-transition-randomdissolve() ms-transition-slide() ms- transition-spiral() ms-transition-stretch() ms-transition-strips() ms-transition-wheel() ms-transition-zigzag() @namespace negative (@counter- style) :not :nth-child :nth-last-child :nth-last-of-type :nth-of-type <number> object-fit object-position offset-block-end offset-block-start offset-inline- end offset-inline-start :only-child :only-of-type opacity opacity() :optional order orientation (@viewport) @ornaments ornaments() orphans :out-of-range outline outline-color outline-offset outline-style outline-width overflow overflow-wrap overflow-x overflow-y Pixelate() pad (@counter-style) padding padding-block-end padding-block-start padding-bottom padding-inline-end padding-inline-start padding-left padding-right padding-top @page page-break-after page-break-before page-break-inside pc <percentage> perspective perspective() perspective-origin place-content !::placeholder pointer-events polygon() <position> position prefix (@counter-style) pt px Q quotes RadialWipe() RandomBars() RandomDissolve() Redirect() RevealTrans() rad radial-gradient() range (@counter-style) <ratio> :read-only :read-write rect() rem repeat() repeating-linear-gradient() repeating-radial-gradient() :required resize <resolution> revert rgb() rgba() :right right @right-bottom :root rotate() rotate3d() rotateX() rotateY() rotateZ() ruby-align ruby-merge ruby-position Shadow() Slide() Spiral() Stretch() Strips() s saturate() scale() scale3d() scaleX() scaleY() scaleZ() :scope scroll-behavior scroll-snap-coordinate scroll-snap-destination scroll-snap-type !::selection sepia() <shape> shape-image-threshold shape-margin shape-outside skew() skewX() skewY() speak-as (@counter-style) src (@font- face) steps() <string> @styleset styleset() @stylistic stylistic() suffix (@counter-style) @supports @swash swash() symbols (@counter-style) symbols() system (@counter-style) tab-size table-layout :target target-counter() target-counters() target-text() text-align text-align-last text-combine-upright text- decoration text-decoration-color text-decoration-line text-decoration-style text-emphasis text-emphasis-color text-emphasis-position text-emphasis-style text-indent text-justify text-orientation text-overflow text-rendering text-shadow text-transform text-underline-position <time> <timing-function> top @top- center touch-action transform transform-box <transform-function> transform-origin transform-style transition transition-delay transition-duration transition-property transition-timing-function translate() translate3d() translateX() translateY() translateZ() turn unicode-bidi unicode-range (@font-face) unset <url> url() user-zoom (@viewport) :valid var() vertical-align vh @viewport visibility :visited vmax vmin vw Wave() Wheel() white-space widows width width (@viewport) will-change word-break word-spacing word-wrap writing-mode Xray() Zigzag() z-index zoom (@viewport) #--* NOPE
you need isolation
Inject DOM elements in the first party page?
Web Components?
scoped styles isolation
Not enough browser support + unstable when it works
Web Components?
iframe?
if you have a fixed ratio or height? sure
iframe adds two requests (HTML + inner JS) and limited
for communication
iframe?
sourceless iframe?
just use the iframe as a rendering target
let iframe = document.createElement("iframe"); iframe.src = "javascript:;";
Browser issues • IE can't access contentWindow without a domain
• Firefox doesn't always fire a load event
iframe.src = isTrident ? "javascript:" + `'<script> window.onload = function()
{ document.domain = "first-party.domain" } %</script>'` : "javascript:;";
setTimeout( renderWithoutLoadEvent, ARBITRARY_TIMEOUT );
an iframe has a fixed height Design issue
you need a JS running on the first party to
set the iframe height
watch the iframe body size?
body content content iframe
watch the iframe body size?
watch a container div in the body size
let lastHeight = 0; function tick() { let height =
root.getBoundingClientRect().height; if(height ##!== lastHeight) { lastHeight = height; iframe.style.height = height + "px"; } requestAnimationFrame(tick); } requestAnimationFrame(tick);
Try not to use global window & document
node.ownerDocument document.defaultView Use these
arrayFromIframe instanceof Array Array.isArray(arrayFromIframe) ({}).toString.call(arrayFromIframe) !!=== "[object Array]" Don’t trust
inheritance
Layers? Modals?
Dropdown ▼
Dropdown ▼ solution 1: expand iframe contents of the first-party
page
Dropdown ▼ solution 2: scroll view
Dropdown ▼ solution 3: more iframes™ r + pageYOffset
let layerManager: (module LayerManager) = environment )== "THIRD_PARTY" ? ((module
ThirdPartyLayerManager): (module LayerManager)) : ((module DefaultLayerManager): (module LayerManager)); module LayerManager = (val layerManager);
ReactDOM.createPortal
No persistent storage No service workers ...
SDK needs to be small
no (or very few) polyfills
Can't break MooTools or Prototype.js
Bundler conflicts { +/* !!... #*/ output: { +/* !!...
#*/ jsonpFunction: "namespaced__define", } }
Booting
domReady?
when DOMContentLoaded or load fire, you don't know if your
booting script is ready
async loop
function checkSdk() { if(window.myBootingFunction) { window.myBootingFunction() } else { setTimeout(checkSdk,
40) } } checkSdk()
third-party analytics?
(function(_, b, e, o, p) { if (_.myTracker) { return;
} _.myTracker = function myTracker() { myTracker.events.push([].slice.call(arguments)); }; myTracker.events = []; o = b.createElement(e); o.src = "https:///example.com/path-to-real-script.js"; p = b.querySelector(e); p.parentNode.insertBefore(o, p); })(window, document, "script");
register events before your actual script has loaded
If you're going to make a third-party widget: keep all
that in mind
the code you made your client install on their page
needs to work forever
you can only add non-breaking changes
tl;dr; styles: you're fucked scripts: you're fucked API: no breaking
change
Thank you Got any questions? ✋