⚛ 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
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
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
- Comments start with #
- Sections start with an @
- 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: ''
})
}
exports.handler = arc.html.get(index)
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
🎁 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!