State of the JAMstack Nation

A presentation at JAMstack_conf London in July 2019 in London, UK by Sarah Drasner

Slide 1

Slide 1

S TAT E O F T H E JA M S TAC K N AT I O N

Slide 2

Slide 2

S TAT E O F T H E JA M S TAC K N AT I O N

Slide 3

Slide 3

Slide 4

Slide 4

Slide 5

Slide 5

Slide 6

Slide 6

Slide 7

Slide 7

Ethernet

Slide 8

Slide 8

Slide 9

Slide 9

Slide 10

Slide 10

JAMstack • JavaScript • API • Markup

Slide 11

Slide 11

DNS BROWSER CDN D ATA B A S E LOAD BALANCER CLOUD STORAGE CACHING SERVICE WEB APP SERVERS JOB QUEUE JOB SERVERS SERVICES

Slide 12

Slide 12

DNS BROWSER CDN

Slide 13

Slide 13

DNS BROWSER CDN SERVICES

Slide 14

Slide 14

JAMstack A modern architecture — Create fast and secure sites and dynamic apps with JavaScript, APIs, and prerendered Markup, … served without web servers.

Slide 15

Slide 15

Slide 16

Slide 16

Slide 17

Slide 17

Slide 18

Slide 18

SA RA H D RAS N E R @ SA RA H _ E D O

Slide 19

Slide 19

DNS BROWSER CDN SERVICES

Slide 20

Slide 20

Slide 21

Slide 21

• Nuxt (Vue.js) • Next (React.js) • Gatsby (React.js) • Eleventy (Vanilla JS) • Jekyll (Ruby) • Hugo (Go) • More and more…

Slide 22

Slide 22

• Contentful • Forestry • Sanity • Netlify CMS • CraftCMS • Decoupled Wordpress • Decoupled Drupal • More and more…

Slide 23

Slide 23

Netlify Function Stripe Vuex Store Layouts Pages Components

Slide 24

Slide 24

Vue Single File Components <template> <div></div> </template> <script> export default { } </script> <style scoped> </style> @sarah_edo

Slide 25

Slide 25

Templates in the pages directory <nuxt-link to=”/product”>Product</nuxt-link> @sarah_edo

Slide 26

Slide 26

Slide 27

Slide 27

Slide 28

Slide 28

Deployed! @sarah_edo

Slide 29

Slide 29

Netlify Function Stripe Vuex Store Layouts Pages Components

Slide 30

Slide 30

functions/index.js exports.handler = async (event, context) =>” { return { statusCode: 200, body: JSON.stringify({ message: “Hi there Tacos”, event }) } } netlify.toml [build] functions = “functions”

Slide 31

Slide 31

Slide 32

Slide 32

Slide 33

Slide 33

Slide 34

Slide 34

yarn add dotenv require(“dotenv”).config() const stripe = require(“stripe”)(process.env.STRIPE_SECRET_KEY), headers = { “Access-Control-Allow-Origin”: “*”, “Access-Control-Allow-Headers”: “Content-Type” }

Slide 35

Slide 35

Slide 36

Slide 36

exports.handler = async (event, context) =>” { if (!event.body || event.httpMethod !==$$ “POST”) { return { statusCode: 400, headers, body: JSON.stringify({ status: “invalid http method” }) } } const data = JSON.parse(event.body) if (!data.stripeToken || !data.stripeAmt || !data.stripeIdempotency) { console.error(“Required information is missing.”) } return { statusCode: 400, headers, body: JSON.stringify({ status: “missing information” }) }

Slide 37

Slide 37

// stripe payment processing begins here try { await stripe.customers .create({ email: data.stripeEmail, source: data.stripeToken }) .then(customer =>” { console.log( starting the charges, amt: ${data.stripeAmt}, email: ${data.stripeEmail} ) return stripe.charges .create( { currency: “usd”, amount: data.stripeAmt, receipt_email: data.stripeEmail, customer: customer.id, description: “Sample Charge” }, { idempotency_key: data.stripeIdempotency } ) .then(result =>” { console.log(Charge created: ${result}) }) })

Slide 38

Slide 38

Netlify Function Stripe Vuex Store AppCard.vue Layouts Pages Components

Slide 39

Slide 39

Slide 40

Slide 40

yarn add vue-stripe-elements-plus

Slide 41

Slide 41

<h3>Please enter your payment details:</h3> <label for=”email”>Email</label> <input id=”email” type=”email” v-model=”stripeEmail” placeholder=”name@example.com” /> <label for=”card”>Credit Card</label> <card class=”stripe-card” id=”card” :class=”{ complete }” stripe=”pk_test_5ThYi0UvX3xwoNdgxxxTxxrG” :options=”stripeOptions” @change=”complete = $event.complete” /> <button class=”pay-with-stripe button” @click=”pay” :disabled=”!complete || !stripeEmail” >Pay with credit card</button>

Slide 42

Slide 42

AppCard.vue pay() { createToken().then(data =>” { const stripeData = { data, stripeEmail: this.stripeEmail }; this.$store.dispatch(“postStripeFunction”, stripeData); }); },

Slide 43

Slide 43

Vuex store export const actions = { async postStripeFunction({ getters, commit }, payload) { commit(“updateCartUI”, “loading”) try { await axios .post( “https://ecommerce-netlify.netlify.com/.netlify/functions/index”, { stripeEmail: payload.stripeEmail, stripeAmt: Math.floor(getters.cartTotal * 100), //it expects the price in cents stripeToken: “tok_visa”, //testing token, later we would use payload.data.token stripeIdempotency: uuidv1() //we use this library to create a unique id }, { headers: { “Content-Type”: “application/json” } } ) .then(res =>” { if (res.status ===&& 200) { commit(“updateCartUI”, “success”) setTimeout(() =>” commit(“clearCart”), 3000) …

Slide 44

Slide 44

Success!

Slide 45

Slide 45

Slide 46

Slide 46

DEMO github.com/sdras/ecommerce-netlify REPO ecommerce-netlify.netlify.com @sarah_edo

Slide 47

Slide 47

• Centered around a developer friendly, Git-based workflow • Designed modularly, consuming other services via APIs • Prebuilt and optimized before being served • Globally distributed and resilient to heavy traffic

Slide 48

Slide 48

• Better performance • Reduced operations cost • Increased security • Cheaper, easier scaling

Slide 49

Slide 49

Slide 50

Slide 50

• 65% LESS EXPENSIVE • AV E R A G E S E R V E R C O N N E C T I O N T I M E + 5 7 %

Slide 51

Slide 51

6x faster N E T L I F Y. C O M / C A S E - S T U D I E S / S M A S H I N G /

Slide 52

Slide 52

Slide 53

Slide 53

Slide 54

Slide 54

What are you going to build?

Slide 55

Slide 55

Thank you! @sarah_edo