Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Third Party Hell
Search
Matthias Le Brun
March 28, 2018
Technology
590
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
130
(why the hell did I) build a GraphQL client for the browser
bloodyowl
0
160
Boxed: bringing algebraic types to TypeScript
bloodyowl
0
210
leveraging (algebraic data) types to make your UI rock @ jsheroes
bloodyowl
0
350
Leveraging (algebraic data) types to make your UI rock solid
bloodyowl
0
530
La drôle d'histoire de JavaScript
bloodyowl
0
420
Healthy Code Collaboration
bloodyowl
0
390
Simplify your UI management with (algebraic data) types
bloodyowl
0
870
Simplify your UI management with (algebraic data) types
bloodyowl
1
600
Other Decks in Technology
See All in Technology
20260929_AmazonGuardDutyの検出通知メールにAWS DevOpsAgentの調査結果を追加する
yhana
1
380
Making AI Agents Safe and Fast- Jev, Obsidian, and the Meta-Harness
x5gtrn
PRO
0
170
「大丈夫そう?」をObservabilityで確かめる
mrmtsu
0
240
Oracle Cloud Infrastructure(OCI):Onboarding Session(はじめてのOCI/Oracle Supportご利⽤ガイド)
oracle4engineer
PRO
3
21k
企業の現実世界をグラフで写し取る
sansantech
PRO
0
210
セルフサービスのオブザーバビリティ基盤をOpenTelemetryで作る / Building a Self-Service Observability Platform with OpenTelemetry
ymotongpoo
3
490
HacobuにおけるFDEとは/登壇資料(戸井田 裕貴)
hacobu
PRO
1
620
LT:「このままでいいのかな?」から一歩踏み出した私のデータキャリア選択〜社会人3年目に上京を決意したリアル〜Snowflake女子会 vol.8
snowwmn0824
0
120
The kernel report
ennael
PRO
1
150
認知負荷を吸収し、プロダクトをまたぐPR Preview基盤の設計事例
taiki45
2
550
顧客の成果創出とプロダクトの成長を 両立するためのFDE
sansantech
PRO
0
520
行動するAIのためのオントロジー | DevRev — Encraft #26.pdf
dvrv_tknrszk
1
610
Featured
See All Featured
The Spectacular Lies of Maps
axbom
PRO
1
1.1k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
530
WCS-LA-2024
lcolladotor
0
840
Exploring anti-patterns in Rails
aemeredith
4
520
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
Odyssey Design
rkendrick25
PRO
2
840
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
340
The untapped power of vector embeddings
frankvandijk
2
1.9k
My Coaching Mixtape
mlcsv
0
330
Claude Code のすすめ
schroneko
67
230k
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? ✋