⚛ React on Lambda with Parcel.js

⚛ React on Lambda with Parcel.js

⚛ Serverless Side Rendering (SSR) on AWS Lambda with React with ParcelJS, Rollup and using arc.codes

🔔🔔🔔 BUZZWORD BINGO

  • ✅ SSR
  • ✅ Lambda
  • ✅ React
  • ✅ ParcelJS
  • ✅ Rollup
  • arc.codes

An elliptical narrative about web servers pre-rendering html content and how to use lambda functions for pre-rendering html content.

I had a

REALLY BIG

question

"Is it possible to pre-render html content without a web server?"

— @brianleroux

Prerendering

  • Why do it?
  • How to do it?
Mostly performance...

Authortime performance

Reuse templates between the client and the server!

Runtime performance

Things just work immediately even without javascript enabled!

Perceived performance

ttfb vs tti

Some devices do not have javascript enabled

  • ☞ eReaders
  • ☞ Low end phones
  • ☞ Screenreaders

Accessibility should always be the strongest reason!

Rendering a Client with React and ParcelJS

Super basic client entry file

One Weird Trick #1

Serverside render function

React JSX syntax needs to be transpiled
Limit transpile time by only transpiling code that absolutely needs it
Another benefit is now any web server (or Node runtime like Lambda) just works!

Serverside render function

let render = require('./src/views')
let express = require('express')
let app = express()

app.get('*', (req, res) => {
  let html = render({path:req.path, state:{}}) 
  res.send(html)
})

Serverside render function

let render = require('./src/views')
let express = require('express')
let app = express()

app.get('*', (req, res) => {
  let html = render({path:req.path, state:{}}) 
  res.send(html)
})

Serverside render function

let render = require('./src/views')
let express = require('express')
let app = express()

app.get('*', (req, res) => {
  let html = render({path:req.path, state:{}}) 
  res.send(html)
})

This is a cringe worthy example!

* routes never happen in practice and probably shouldn't anyhow

But what happens when the servers all go away?

Billing is now measured in milliseconds of compute and it is super cheap
Provisioning is now measured in minutes not hours
Deployments are now measured in seconds not minutes or hours
Faster provisioning and deploys equals more iteration speed (lead time to production is lower than competitors)

Cloud Functions Vendors

  • AWS Lambda
  • Azure Cloud Functions
  • Google Cloud Functions

Power Laws

Amazon not only pioneered this space but dominates it by multiples on all metrics: services, features, revenue, uptime, you-name-it

Power Laws

Broad adoption is not lock-in! At this point adoption de-risking by opt-in; newer hungrier competitors will get the advantages of speed to scale and pay-for-use even if you do not!

Primitives over Frameworks

  • API gateway
  • Event gateway
  • Managed durable persistence
  • Blobstore and CDN
  • Logging, monitoring and analytics

AWS primitives

  • HTTP handler Lambdas using Route53, and the literally named API Gateway
  • SNS and AWS IoT enable pub/sub and MQTT over Web Sockets respectively
  • DynamoDB + autoscaling: durable and predictable persistence
  • S3 + CloudFront
  • CloudWatch

Primitives over Frameworks

  • API gateway
  • Event gateway
  • Managed durable persistence
  • Blobstore and CDN
  • Logging, monitoring and analytics

Lambda is the glue of AWS services! From DynamoDB streams to CloudWatch Events scheduled functions the capability continues to grow more and more sophisticated

Functions as a Service

Focus on application logic instead of maintaining infra; no more os upgrades, package management, security patches, orchestration tasks and load balancing

Pure isolation

Functions are faster to deploy, only use what they need so they start up faster and are far easier to reason about when debugging

Peace of mind

Your code scales transparently so you can focus on customer features and fixes with total confidence the infra side is taken care of

Lets have a moment of silence and show our thanks to the servers

Servers did a good job and taught us many important lessons

Infrastructure as code

Old school tools: Chef, Puppet, Ansible

Architecture as Text

New school tools: SAM, Serverless™, Terraform, JSF Architect

JS Foundation Architect

We mostly just call it "arc". The code was granted to the JSF in 2017 because we believe open governance is an important facet to open source
The "arc" name comes from the manifest file (.arc) which shamelessly copies the rc file convention of UNIX yore (like: .vimrc, .bashrc, etc) and stands for "Amazon Run Commands"
.arc designed to address the problems with YAML and JSON as a manifest
.arc uses project local npm scripts instead of global cli tools
.arc is extremely fast; blazing even! ;)
.arc is tuned for a higher level developer experience while maintaining a close relationship to the low level AWS primitives
Is running in production having been extracted from begin.com which is an web and Slack app for tasking

.arc has three simple rules

  1. Comments start with #
  2. Sections start with an @
  3. Everything else becomes AWS infrastructure
a complete .arc example
@app
hello

@html
get /
post /likes

@json
get /likes
The .arc above would generate three lambda functions: src/html/get-index, src/html/post-likes and src/json/get-likes
Lets look at the generated cloud function code
src/html/get-index/index.js
var arc = require('@architect/functions')

function index(req, res) {
  res({
    html: 'hello world'
  })
}

exports.handler = arc.html.get(index)
Other .arc tidbits
First class support for isolated staging and production envs
npm start runs the code locally
Session state is enabled by default
.arc is deliberately constrained and terse
Lets get back to server(less) rendering!
HTTP lambdas need to run a copy of your clientside app in the lambda NodeJS runtime to resolve an html string given a particular state

Attempt #1

npm i react react-dom --save --production

Attempt #1 Failed!

Ultimately installs 10mb of node_modules slowing down lambda unacceptably

Attempt #2

Rollup the render function into a single file module

🎉 worked beautifully!

🎁 Summary

Build clientside assets with Parcel because srsly y not
🎯 Build client into a Node function that accepts state and returns a string
🧐 Parcel and Rollup both inherited .babelrc kind of neat

Conclusion

Pre-rendering html content is possible without servers too!

Thx!
Source Code on Github

References arc.codes
parceljs.org
rollupjs.org

Author brian.io