Serverless and React
(It's Just Sleight Of Hand)
Photo by Alex Block
Marina Miranovich
@obnoxious_mari
2
Nice to meet you!
3
Solution Architect in
Agenda
Part 1. Exposition
Part 2. Main story
Part 3. Resolution
4
5
Part 1.
Exposition
Services I used
S3 Assets storage
IAM Manages access rights
API Gateway URL for the site
CloudFormation Deployment
AWS Lambda
6
7
Important!
I highly encourage you to attempt all demos yourself at home.*
And it’s
free!
7
What is AWS Lambda?
8
Scaling
9
Part 2.
Main story
https://github.com/Marina-Miranovich/lambda-react
http://bit.ly/react-lambda
11
1212
How it works?
http://foo.com GET foo.com/
Lambda renders
the page
API Gateway
triggers Lambda
GET bundle.js
S3: Bundle.js,
main.css, fonst,
etc.
User
Browser
13
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
└── yarn.lock
Project structure
config
package.json
serverless.yml
src
14
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
└── yarn.lock
config
├── env.js
├── jest
├── paths.js
├── polyfills.js
├── webpack.config.dev.js
├── webpack.config.lambda.js
├── webpack.config.prod.js
└── webpackDevServer.config.js
webpack.config.lambda.js
15
Lambda Webpack config
1 module.exports = {
2 entry: slsw.lib.entries,
3 target: 'node',
4 module: {
5 loaders: [
6 { test: /.js$/, loaders: ['babel-loader'], include: path.resolve(__dirname, '../src'), exclude:
/node_modules/ },
7 { test: /.css$/, loaders: ['node-style-loader','css-loader?importLoaders=1'], exclude: /node_modules/ },
8 { test: [/.png$/, /.jpg$/], loader: 'url-loader', options: { limit: 10000, mimetype: 'image/png' } }
9 ],
10 },
11 output: {
12 libraryTarget: 'commonjs',
13 path: path.join(__dirname, '../.webpack'),
14 filename: '[name].js',
15 },
16 };
target: 'node',
entry: slsw.lib.entries,
libraryTarget: 'commonjs',
16
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
└── yarn.lock
config
package.json
serverless.yml
src
17
package.json
1 {
2 "name": "lambda-react-demo",
3 "version": "1.0.0",
4 "scripts": {
5 "start": "node scripts/start.js",
6 "build": "node scripts/build.js",
7 "lambda": "sls offline --port 8000 start",
8 "deploy:lambda": "sls deploy"
9 },
10 "dependencies": {
...
"lambda": "sls offline --port 8000 start"
"deploy:lambda": "sls deploy"
18
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
└── yarn.lock
19
serverless.yml
1 service:
2 name: lambda-react-demo
3 plugins:
4 - serverless-webpack
5 - serverless-offline
6 provider:
7 name: aws
8 runtime: nodejs6.10
9 functions:
10 renderPage:
11 handler: src/lambda/handler.renderPage
12 events:
13 - http:
14 method: GET
15 path: /
16 custom:
17 webpack: "./config/webpack.config.lambda.js"
handler: src/lambda/handler.renderPage
webpack: "./config/webpack.config.lambda.js"20
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
└── yarn.lock
config
package.json
serverless.yml
src
21
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
└── yarn.lock
src
├── actions
├── apis
├── components
├── index.css
├── index.js
├── lambda
├── reducers
└── sagas
lambda
22
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
│ ├── actions
│ ├── apis
│ ├── components
│ ├── index.css
│ ├── index.js
│ ├── lambda
│ ├── reducers
│ └── sagas
└── yarn.lock
lambda
├── handler.js
└── renderer.jsrenderer.js
handler.js
23
Lambda handler src/lambda/handler.js
1 import render from './renderer';
2
3 const createResponse = (html) => {
4 return {
5 statusCode: 200,
6 headers: {
7 "Content-Type": "text/html; charset=utf-8"
8 },
9 body: html
10 };
11 };
12
13 export const renderPage = (event, context, cb) => {
14 render()
15 .then((html) => cb(null, createResponse(html)))
16 .catch(e => cb(e));
17 };
13 export const renderPage = (event, context, cb) => {
14 render()
15 .then((html) => cb(null, createResponse(html)))
16 .catch(e => cb(e));.catch(e => cb(e));
createResponse(html)
24
Lambda handler src/lambda/handler.js
1 import render from './renderer';
2
3 const createResponse = (html) => {
4 return {
5 statusCode: 200,
6 headers: {
7 "Content-Type": "text/html; charset=utf-8"
8 },
9 body: html
10 };
11 };
12
13 export const renderPage = (event, context, cb) => {
14 render()
15 .then((html) => cb(null, createResponse(html)))
16 .catch(e => cb(e));
17 };
statusCode: 200,
"Content-Type": "text/html; charset=utf-8"
25
Lambda handler src/lambda/handler.js
1 import render from './renderer';
2
3 const createResponse = (html) => {
4 return {
5 statusCode: 200,
6 headers: {
7 "Content-Type": "text/html; charset=utf-8"
8 },
9 body: html
10 };
11 };
12
13 export const renderPage = (event, context, cb) => {
14 render()
15 .then((html) => cb(null, createResponse(html)))
16 .catch(e => cb(e));
17 };
14 render()
15 .then((html) => cb(null, createResponse(html)))
16 .catch(e => cb(e));
render()
1 import render from './renderer';
26
Project structure
lambda-react
├── README.md
├── config
├── package.json
├── public
├── scripts
├── serverless.yml
├── src
│ ├── actions
│ ├── apis
│ ├── components
│ ├── index.css
│ ├── index.js
│ ├── lambda
│ ├── reducers
│ └── sagas
└── yarn.lock
lambda
├── handler.js
└── renderer.jsrenderer.js
handler.js
27
Inside src/lambda/renderer.js
1. Isomorphic application
2828
Inside src/lambda/renderer.js
1. Isomorphic application
2. Error handling
2929
Error handling src/lambda/renderer.js
1 const render = () => {
2 return new Promise((resolve, reject) => {
30
Inside src/lambda/renderer.js
1. Isomorphic application
2. Error handling
3. Local environment vs. AWS
3131
JS Bundle src/lambda/renderer.js
const bundleUrl = process.env.NODE_ENV === 'AWS' ?
AWS_URL : LOCAL_URL;
...
<script type="text/javascript" src="${bundleUrl}"></script>
32
JS Bundle serverless.yml
...
1 functions:
2 renderPage:
3 handler: src/lambda/handler.renderPage
4 environment:
5 NODE_ENV: "AWS"
...
NODE_ENV: "AWS"
33
34
Part 3.
Resolution
Serverless: advantages and pitfalls
35
Serverless: advantages and pitfalls
https://serverless.com/blog/when-why-not-use-serverless/35
What else you can do with
cloud functions?
37
Anything
you’d
like*
36 * If it’s within cloud functions limitations
What else you can do with cloud functions?
HTTP
services
IoT Chat Bots
Image/Video
conversions
Machine
Learning
Batch Jobs
37
If not AWS
then what?
39
Google
Azure
IBM
Twillio
38
Open Source!
• Iron functions
• Fnproject
• Openfaas
• Apache OpenWhisk
• Kubeless
• Fission
• Funktion
4039
Thank you!
@obnoxious_mariMarina-Miranovich obnoxious_marie

Serverless and React

  • 1.
    Serverless and React (It'sJust Sleight Of Hand) Photo by Alex Block Marina Miranovich @obnoxious_mari
  • 2.
  • 3.
    Nice to meetyou! 3 Solution Architect in
  • 4.
    Agenda Part 1. Exposition Part2. Main story Part 3. Resolution 4
  • 5.
  • 6.
    Services I used S3Assets storage IAM Manages access rights API Gateway URL for the site CloudFormation Deployment AWS Lambda 6
  • 7.
    7 Important! I highly encourageyou to attempt all demos yourself at home.* And it’s free! 7
  • 8.
    What is AWSLambda? 8
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
    How it works? http://foo.comGET foo.com/ Lambda renders the page API Gateway triggers Lambda GET bundle.js S3: Bundle.js, main.css, fonst, etc. User Browser 13
  • 14.
    lambda-react ├── README.md ├── config ├──package.json ├── public ├── scripts ├── serverless.yml ├── src └── yarn.lock Project structure config package.json serverless.yml src 14
  • 15.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src └── yarn.lock config ├── env.js ├── jest ├── paths.js ├── polyfills.js ├── webpack.config.dev.js ├── webpack.config.lambda.js ├── webpack.config.prod.js └── webpackDevServer.config.js webpack.config.lambda.js 15
  • 16.
    Lambda Webpack config 1module.exports = { 2 entry: slsw.lib.entries, 3 target: 'node', 4 module: { 5 loaders: [ 6 { test: /.js$/, loaders: ['babel-loader'], include: path.resolve(__dirname, '../src'), exclude: /node_modules/ }, 7 { test: /.css$/, loaders: ['node-style-loader','css-loader?importLoaders=1'], exclude: /node_modules/ }, 8 { test: [/.png$/, /.jpg$/], loader: 'url-loader', options: { limit: 10000, mimetype: 'image/png' } } 9 ], 10 }, 11 output: { 12 libraryTarget: 'commonjs', 13 path: path.join(__dirname, '../.webpack'), 14 filename: '[name].js', 15 }, 16 }; target: 'node', entry: slsw.lib.entries, libraryTarget: 'commonjs', 16
  • 17.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src └── yarn.lock config package.json serverless.yml src 17
  • 18.
    package.json 1 { 2 "name":"lambda-react-demo", 3 "version": "1.0.0", 4 "scripts": { 5 "start": "node scripts/start.js", 6 "build": "node scripts/build.js", 7 "lambda": "sls offline --port 8000 start", 8 "deploy:lambda": "sls deploy" 9 }, 10 "dependencies": { ... "lambda": "sls offline --port 8000 start" "deploy:lambda": "sls deploy" 18
  • 19.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src └── yarn.lock 19
  • 20.
    serverless.yml 1 service: 2 name:lambda-react-demo 3 plugins: 4 - serverless-webpack 5 - serverless-offline 6 provider: 7 name: aws 8 runtime: nodejs6.10 9 functions: 10 renderPage: 11 handler: src/lambda/handler.renderPage 12 events: 13 - http: 14 method: GET 15 path: / 16 custom: 17 webpack: "./config/webpack.config.lambda.js" handler: src/lambda/handler.renderPage webpack: "./config/webpack.config.lambda.js"20
  • 21.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src └── yarn.lock config package.json serverless.yml src 21
  • 22.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src └── yarn.lock src ├── actions ├── apis ├── components ├── index.css ├── index.js ├── lambda ├── reducers └── sagas lambda 22
  • 23.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src │ ├── actions │ ├── apis │ ├── components │ ├── index.css │ ├── index.js │ ├── lambda │ ├── reducers │ └── sagas └── yarn.lock lambda ├── handler.js └── renderer.jsrenderer.js handler.js 23
  • 24.
    Lambda handler src/lambda/handler.js 1import render from './renderer'; 2 3 const createResponse = (html) => { 4 return { 5 statusCode: 200, 6 headers: { 7 "Content-Type": "text/html; charset=utf-8" 8 }, 9 body: html 10 }; 11 }; 12 13 export const renderPage = (event, context, cb) => { 14 render() 15 .then((html) => cb(null, createResponse(html))) 16 .catch(e => cb(e)); 17 }; 13 export const renderPage = (event, context, cb) => { 14 render() 15 .then((html) => cb(null, createResponse(html))) 16 .catch(e => cb(e));.catch(e => cb(e)); createResponse(html) 24
  • 25.
    Lambda handler src/lambda/handler.js 1import render from './renderer'; 2 3 const createResponse = (html) => { 4 return { 5 statusCode: 200, 6 headers: { 7 "Content-Type": "text/html; charset=utf-8" 8 }, 9 body: html 10 }; 11 }; 12 13 export const renderPage = (event, context, cb) => { 14 render() 15 .then((html) => cb(null, createResponse(html))) 16 .catch(e => cb(e)); 17 }; statusCode: 200, "Content-Type": "text/html; charset=utf-8" 25
  • 26.
    Lambda handler src/lambda/handler.js 1import render from './renderer'; 2 3 const createResponse = (html) => { 4 return { 5 statusCode: 200, 6 headers: { 7 "Content-Type": "text/html; charset=utf-8" 8 }, 9 body: html 10 }; 11 }; 12 13 export const renderPage = (event, context, cb) => { 14 render() 15 .then((html) => cb(null, createResponse(html))) 16 .catch(e => cb(e)); 17 }; 14 render() 15 .then((html) => cb(null, createResponse(html))) 16 .catch(e => cb(e)); render() 1 import render from './renderer'; 26
  • 27.
    Project structure lambda-react ├── README.md ├──config ├── package.json ├── public ├── scripts ├── serverless.yml ├── src │ ├── actions │ ├── apis │ ├── components │ ├── index.css │ ├── index.js │ ├── lambda │ ├── reducers │ └── sagas └── yarn.lock lambda ├── handler.js └── renderer.jsrenderer.js handler.js 27
  • 28.
  • 29.
    Inside src/lambda/renderer.js 1. Isomorphicapplication 2. Error handling 2929
  • 30.
    Error handling src/lambda/renderer.js 1const render = () => { 2 return new Promise((resolve, reject) => { 30
  • 31.
    Inside src/lambda/renderer.js 1. Isomorphicapplication 2. Error handling 3. Local environment vs. AWS 3131
  • 32.
    JS Bundle src/lambda/renderer.js constbundleUrl = process.env.NODE_ENV === 'AWS' ? AWS_URL : LOCAL_URL; ... <script type="text/javascript" src="${bundleUrl}"></script> 32
  • 33.
    JS Bundle serverless.yml ... 1functions: 2 renderPage: 3 handler: src/lambda/handler.renderPage 4 environment: 5 NODE_ENV: "AWS" ... NODE_ENV: "AWS" 33
  • 34.
  • 35.
  • 36.
    Serverless: advantages andpitfalls https://serverless.com/blog/when-why-not-use-serverless/35
  • 37.
    What else youcan do with cloud functions? 37 Anything you’d like* 36 * If it’s within cloud functions limitations
  • 38.
    What else youcan do with cloud functions? HTTP services IoT Chat Bots Image/Video conversions Machine Learning Batch Jobs 37
  • 39.
    If not AWS thenwhat? 39 Google Azure IBM Twillio 38
  • 40.
    Open Source! • Ironfunctions • Fnproject • Openfaas • Apache OpenWhisk • Kubeless • Fission • Funktion 4039
  • 41.