WHY JSON

IS THE ONLY DB

YOU NEED

A serious talk by Titus Woo

Hello, I'm Titus πŸ‘‹

You can trust me

😏

DO YOU EVEN DEPLOY, BRO?

Deployment types

Kraken apps (front-tier)

Typhon apps (mid-tier)

NPM packages

Static assets

Straightforward in isolation

Node.js

Mid-tier (Typhon)

NPM

CDN

Messier in practice

Used in different places

  • Summary Page
  • Money Page
  • Interstitial-after-login page
  • Help page
  • Marketing pages
  • etc.
import React from 'react'
import Dashboard from './Dashboard'
import { AdBanner } from '@paypalcorp/pp-ad-banner'

const App = () => (
    <html>
        <head>
            <title>Dashboard</title>
        </head>
        <body>
            <AdBanner />
            <Dashboard />
        </body>
    </html>
)

Usage

Teams integrate! πŸŽ‰

  • Summary Page
  • Money Page
  • Interstitial-after-login page
  • Help page
  • Marketing pages
  • etc.
import React from 'react'
import Dashboard from './Dashboard'
import { AdBanner } from '@paypalcorp/pp-ad-banner'

const App = () => (
    <html>
        <head>
            <title>Dashboard</title>
        </head>
        <body>
            <AdBanner />
            <Dashboard />
        </body>
    </html>
)

Usage

The End

πŸ˜‡

Ad team makes some improvements...

Asset optimization

Asset optimization

CDN need updating

cash-flow-ad-lg.jpg
cash-flow-ad-sm.jpg

Deploy assets to CDN

API needs updating

Deploy updated search-ads api

Provides URL for small and large banner images.

pp-ad-banner

Display optimized image based on device

Deploy new version of NPM package

<img srcset="cash-flow-ad-sm.jpg 160w,
             cash-flow-ad-lg.jpg 940w"
     sizes="(max-width: 160px) 160px,
            940px"
     src="cash-flow-ad-lg.jpg" />

Accessibility updates

pp-ad-banner

Include alt text in the ad image

Deploy new version of NPM package

<img srcset="cash-flow-ad-sm.jpg 160w,
             cash-flow-ad-lg.jpg 940w"
     sizes="(max-width: 160px) 160px,
            940px"
     src="cash-flow-ad-lg.jpg"
     alt="An offer banner. It says, β€˜Facing a cash flow gap? A PayPal business Loan could help. Apply…"
 />

API needs updating

Deploy updated API

Teams integrate! πŸŽ‰

  • Summary Page πŸ˜ŽπŸ‘
  • Money Page πŸ˜„πŸ‘πŸΌ
  • Interstitial-after-login page πŸ™‹πŸ½β€β™€οΈβš‘οΈ - removing React
  • Another page πŸ€”β° - when do we need to update?
  • Another page πŸ™‹πŸ»β€β™‚οΈπŸ˜­ - using older version of React.
  • etc.

Every team needs to update NPM package and redeploy

Dependency on React

Dependent on React 16

Easy to integrate, at cost of all data orchestration done in the browser

Lots of XHR requests in the browser

Downsides

There's a better way!

πŸ˜‚

How things work

right now

Let's change

things up! πŸŽ‰

{
    "html": "",
    "css": "",
    "js": ""
}
<div id="ad">loading ad...</div>
<script>
    fetch('paypal.com/banner-ad')
        .then(banner => banner.json())
        .then(banner => {
            document.getElementById('ad').innerHTML = banner.html
            const cssNode = document.createTextNode(banner.css)
            const styleNode = document.createElement('style')
            styleNode.appendChild(cssNode)
            document.head.append(styleNode)
        })
</script>

Loads at runtime!

Loads at runtime!

Cold start:

{
    "html": "",
    "css": "",
    "js": ""
}
  • Banner ad border changed from red to green.
  • Make changes in banner-ad code.
  • Redeploy. Done!

Reload to get new changes!

banner-ad

Node.js

dashboard

Node.js

Let's review πŸ•°

Every team needs to update NPM package and redeploy

to get new changes

Dependency on React

Dependent on React 16

Easy to integrate, at cost of all data orchestration done in the browser

Lots of XHR requests in the browser

Downsides of prior solution

We can use this for ALL THE THINGS

  • Owned by different teams
  • Updated independently
  • Refresh to get latest changes
  • Technology agnostic
  • Caching on a per-fragment basis

These are fragments

We can make this even better!

(on 3G simulated connection)

Client-side rendering

has its limits

SSR to the rescue!

request.get('https://paypal.com/fragments/ad-banner', (e, r, body) => {
    const adFragment = JSON.parse(body)
    res.send(`
        <html>
            <head>
                <title>Dashboard</title>
                <style>${adFragment.css}</style>
            </head>
            <body>
                <h1>PayPal Dashboard</h1>
                <div id="ad">${adFragment.html}</div>
                <script>${adFragment.js}</script>
            </body>
        </html>
    `)
})

Before (client-side only)

After (server-side rendered)

πŸ‘πŸ‘

{
    "html": "<div id=\"banner-ad-fragment\"><img src=\"paypalobjects.com/ad-banner-lg.jpg\" /></div>",
    "css": "#banner-ad-fragment { background-color: gray; }",
    "js": "document.getElementById('banner-ad-fragment').addEventListener(() => { console.log('hi') })"
}

More optimization

  • Fragment JSON payload can be quite large
  • CSS and JS are inlined in the HTML
  • CSS and JS are pulled from origin every time
fetch('/banner')
{
    "html": "<div id=\"banner-ad-fragment\"><img src=\"paypalobjects.com/ad-banner-lg.jpg\" /></div>",
    "css": "https://paypalobjects.com/wlke925224s.css",
    "js": "https://paypalobjects.com/eesl33t3ls1.js"
}

Offload to the CDN

  • CSS and JS on the CDN
  • Better/more granular caching
  • No more round-trips for files that rarely change

Offload to the CDN

What about completely static pages?

Offload to the CDN

We can cache that too πŸ˜‡

{
    "html": "https://paypalobjects.com/91o4mnzke3.html",
    "css": "https://paypalobjects.com/wlke925224s.css",
    "js": "https://paypalobjects.com/eesl33t3ls1.js"
}
Cache-Control: public, max-age=31536000 Β 

Device-optimized rendering

  • header-fragment endpoint detects mobile user agent
  • returns fragment optimized for mobile only
  • HTML, CSS, JS do not contain any code for desktop version
fetch('/header-fragment')

Just the beginning πŸŽ‰

Service Workers

Local storage

Pre-load

So....

Gotcha!

πŸ˜‚

thanks

πŸ™

@tituswoo

4 USE CASES

#1

Shared Experiences

How we ship code without redeploying anything

By Titus Woo

How we ship code without redeploying anything

Learn how we built a micro-frontend architecture which we've deployed at PayPal! It lets us break up large front-end experiences into smaller, technology-agnostic modules that can be imported anywhere in any app at run-time. This lets us redeploy features and UI instantly to dependent teams without them having to redeploy their apps.

  • 82